forked from Minki/linux
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:
commit
c4755d16fc
@ -35,6 +35,7 @@ extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
|
||||
* zero-initialized data and COW.
|
||||
*/
|
||||
struct page *empty_zero_page;
|
||||
EXPORT_SYMBOL(empty_zero_page);
|
||||
|
||||
/*
|
||||
* The pmd table for the upper-most set of pages.
|
||||
|
@ -69,6 +69,7 @@ void __init m68k_setup_node(int node)
|
||||
*/
|
||||
|
||||
void *empty_zero_page;
|
||||
EXPORT_SYMBOL(empty_zero_page);
|
||||
|
||||
void show_mem(void)
|
||||
{
|
||||
|
@ -282,3 +282,5 @@ EXPORT_SYMBOL(do_BUG);
|
||||
|
||||
/* Sun Power Management Idle Handler */
|
||||
EXPORT_SYMBOL(pm_idle);
|
||||
|
||||
EXPORT_SYMBOL(empty_zero_page);
|
||||
|
@ -160,6 +160,7 @@ extern unsigned int sparc_ramdisk_image;
|
||||
extern unsigned int sparc_ramdisk_size;
|
||||
|
||||
struct page *mem_map_zero __read_mostly;
|
||||
EXPORT_SYMBOL(mem_map_zero);
|
||||
|
||||
unsigned int sparc64_highest_unlocked_tlb_ent __read_mostly;
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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,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);
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
#include <linux/buffer_head.h>
|
||||
#include <linux/jbd2.h>
|
||||
#include <linux/ext4_fs.h>
|
||||
#include "ext4.h"
|
||||
|
||||
#ifdef EXT4FS_DEBUG
|
||||
|
||||
|
@ -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
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* linux/include/linux/ext4_fs.h
|
||||
* ext4.h
|
||||
*
|
||||
* Copyright (C) 1992, 1993, 1994, 1995
|
||||
* Remy Card (card@masi.ibp.fr)
|
||||
@ -13,14 +13,13 @@
|
||||
* Copyright (C) 1991, 1992 Linus Torvalds
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_EXT4_FS_H
|
||||
#define _LINUX_EXT4_FS_H
|
||||
#ifndef _EXT4_H
|
||||
#define _EXT4_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/magic.h>
|
||||
|
||||
#include <linux/ext4_fs_i.h>
|
||||
#include "ext4_i.h"
|
||||
|
||||
/*
|
||||
* The second extended filesystem constants/structures
|
||||
@ -176,8 +175,7 @@ struct ext4_group_desc
|
||||
#define EXT4_BG_INODE_ZEROED 0x0004 /* On-disk itable initialized to zero */
|
||||
|
||||
#ifdef __KERNEL__
|
||||
#include <linux/ext4_fs_i.h>
|
||||
#include <linux/ext4_fs_sb.h>
|
||||
#include "ext4_sb.h"
|
||||
#endif
|
||||
/*
|
||||
* Macro-instructions used to manage group descriptors
|
||||
@ -231,6 +229,7 @@ struct ext4_group_desc
|
||||
#define EXT4_TOPDIR_FL 0x00020000 /* Top of directory hierarchies*/
|
||||
#define EXT4_HUGE_FILE_FL 0x00040000 /* Set to each huge file */
|
||||
#define EXT4_EXTENTS_FL 0x00080000 /* Inode uses extents */
|
||||
#define EXT4_EXT_MIGRATE 0x00100000 /* Inode is migrating */
|
||||
#define EXT4_RESERVED_FL 0x80000000 /* reserved for ext4 lib */
|
||||
|
||||
#define EXT4_FL_USER_VISIBLE 0x000BDFFF /* User visible flags */
|
||||
@ -1049,8 +1048,7 @@ extern int ext4_block_truncate_page(handle_t *handle, struct page *page,
|
||||
struct address_space *mapping, loff_t from);
|
||||
|
||||
/* ioctl.c */
|
||||
extern int ext4_ioctl (struct inode *, struct file *, unsigned int,
|
||||
unsigned long);
|
||||
extern long ext4_ioctl(struct file *, unsigned int, unsigned long);
|
||||
extern long ext4_compat_ioctl (struct file *, unsigned int, unsigned long);
|
||||
|
||||
/* migrate.c */
|
||||
@ -1204,4 +1202,4 @@ extern int ext4_get_blocks_wrap(handle_t *handle, struct inode *inode,
|
||||
int extend_disksize);
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
#endif /* _LINUX_EXT4_FS_H */
|
||||
#endif /* _EXT4_H */
|
@ -16,10 +16,10 @@
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_EXT4_EXTENTS
|
||||
#define _LINUX_EXT4_EXTENTS
|
||||
#ifndef _EXT4_EXTENTS
|
||||
#define _EXT4_EXTENTS
|
||||
|
||||
#include <linux/ext4_fs.h>
|
||||
#include "ext4.h"
|
||||
|
||||
/*
|
||||
* With AGGRESSIVE_TEST defined, the capacity of index/leaf blocks
|
||||
@ -228,5 +228,5 @@ extern int ext4_ext_search_left(struct inode *, struct ext4_ext_path *,
|
||||
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 /* _LINUX_EXT4_EXTENTS */
|
||||
#endif /* _EXT4_EXTENTS */
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* linux/include/linux/ext4_fs_i.h
|
||||
* ext4_i.h
|
||||
*
|
||||
* Copyright (C) 1992, 1993, 1994, 1995
|
||||
* Remy Card (card@masi.ibp.fr)
|
||||
@ -13,8 +13,8 @@
|
||||
* Copyright (C) 1991, 1992 Linus Torvalds
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_EXT4_FS_I
|
||||
#define _LINUX_EXT4_FS_I
|
||||
#ifndef _EXT4_I
|
||||
#define _EXT4_I
|
||||
|
||||
#include <linux/rwsem.h>
|
||||
#include <linux/rbtree.h>
|
||||
@ -164,4 +164,4 @@ struct ext4_inode_info {
|
||||
spinlock_t i_prealloc_lock;
|
||||
};
|
||||
|
||||
#endif /* _LINUX_EXT4_FS_I */
|
||||
#endif /* _EXT4_I */
|
@ -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;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* linux/include/linux/ext4_jbd2.h
|
||||
* ext4_jbd2.h
|
||||
*
|
||||
* Written by Stephen C. Tweedie <sct@redhat.com>, 1999
|
||||
*
|
||||
@ -12,12 +12,12 @@
|
||||
* Ext4-specific journaling extensions.
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_EXT4_JBD2_H
|
||||
#define _LINUX_EXT4_JBD2_H
|
||||
#ifndef _EXT4_JBD2_H
|
||||
#define _EXT4_JBD2_H
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/jbd2.h>
|
||||
#include <linux/ext4_fs.h>
|
||||
#include "ext4.h"
|
||||
|
||||
#define EXT4_JOURNAL(inode) (EXT4_SB((inode)->i_sb)->s_journal)
|
||||
|
||||
@ -228,4 +228,4 @@ static inline int ext4_should_writeback_data(struct inode *inode)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* _LINUX_EXT4_JBD2_H */
|
||||
#endif /* _EXT4_JBD2_H */
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* linux/include/linux/ext4_fs_sb.h
|
||||
* ext4_sb.h
|
||||
*
|
||||
* Copyright (C) 1992, 1993, 1994, 1995
|
||||
* Remy Card (card@masi.ibp.fr)
|
||||
@ -13,8 +13,8 @@
|
||||
* Copyright (C) 1991, 1992 Linus Torvalds
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_EXT4_FS_SB
|
||||
#define _LINUX_EXT4_FS_SB
|
||||
#ifndef _EXT4_SB
|
||||
#define _EXT4_SB
|
||||
|
||||
#ifdef __KERNEL__
|
||||
#include <linux/timer.h>
|
||||
@ -145,4 +145,4 @@ struct ext4_sb_info {
|
||||
struct ext4_locality_group *s_locality_groups;
|
||||
};
|
||||
|
||||
#endif /* _LINUX_EXT4_FS_SB */
|
||||
#endif /* _EXT4_SB */
|
@ -32,7 +32,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>
|
||||
@ -40,8 +39,9 @@
|
||||
#include <linux/string.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/falloc.h>
|
||||
#include <linux/ext4_fs_extents.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include "ext4_jbd2.h"
|
||||
#include "ext4_extents.h"
|
||||
|
||||
|
||||
/*
|
||||
@ -308,7 +308,7 @@ corrupted:
|
||||
}
|
||||
|
||||
#define ext4_ext_check_header(inode, eh, depth) \
|
||||
__ext4_ext_check_header(__FUNCTION__, inode, eh, depth)
|
||||
__ext4_ext_check_header(__func__, inode, eh, depth)
|
||||
|
||||
#ifdef EXT_DEBUG
|
||||
static void ext4_ext_show_path(struct inode *inode, struct ext4_ext_path *path)
|
||||
@ -614,7 +614,7 @@ static int ext4_ext_insert_index(handle_t *handle, struct inode *inode,
|
||||
|
||||
ix->ei_block = cpu_to_le32(logical);
|
||||
ext4_idx_store_pblock(ix, ptr);
|
||||
curp->p_hdr->eh_entries = cpu_to_le16(le16_to_cpu(curp->p_hdr->eh_entries)+1);
|
||||
le16_add_cpu(&curp->p_hdr->eh_entries, 1);
|
||||
|
||||
BUG_ON(le16_to_cpu(curp->p_hdr->eh_entries)
|
||||
> le16_to_cpu(curp->p_hdr->eh_max));
|
||||
@ -736,7 +736,7 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode,
|
||||
}
|
||||
if (m) {
|
||||
memmove(ex, path[depth].p_ext-m, sizeof(struct ext4_extent)*m);
|
||||
neh->eh_entries = cpu_to_le16(le16_to_cpu(neh->eh_entries)+m);
|
||||
le16_add_cpu(&neh->eh_entries, m);
|
||||
}
|
||||
|
||||
set_buffer_uptodate(bh);
|
||||
@ -753,8 +753,7 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode,
|
||||
err = ext4_ext_get_access(handle, inode, path + depth);
|
||||
if (err)
|
||||
goto cleanup;
|
||||
path[depth].p_hdr->eh_entries =
|
||||
cpu_to_le16(le16_to_cpu(path[depth].p_hdr->eh_entries)-m);
|
||||
le16_add_cpu(&path[depth].p_hdr->eh_entries, -m);
|
||||
err = ext4_ext_dirty(handle, inode, path + depth);
|
||||
if (err)
|
||||
goto cleanup;
|
||||
@ -817,8 +816,7 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode,
|
||||
if (m) {
|
||||
memmove(++fidx, path[i].p_idx - m,
|
||||
sizeof(struct ext4_extent_idx) * m);
|
||||
neh->eh_entries =
|
||||
cpu_to_le16(le16_to_cpu(neh->eh_entries) + m);
|
||||
le16_add_cpu(&neh->eh_entries, m);
|
||||
}
|
||||
set_buffer_uptodate(bh);
|
||||
unlock_buffer(bh);
|
||||
@ -834,7 +832,7 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode,
|
||||
err = ext4_ext_get_access(handle, inode, path + i);
|
||||
if (err)
|
||||
goto cleanup;
|
||||
path[i].p_hdr->eh_entries = cpu_to_le16(le16_to_cpu(path[i].p_hdr->eh_entries)-m);
|
||||
le16_add_cpu(&path[i].p_hdr->eh_entries, -m);
|
||||
err = ext4_ext_dirty(handle, inode, path + i);
|
||||
if (err)
|
||||
goto cleanup;
|
||||
@ -1369,7 +1367,7 @@ int ext4_ext_try_to_merge(struct inode *inode,
|
||||
* sizeof(struct ext4_extent);
|
||||
memmove(ex + 1, ex + 2, len);
|
||||
}
|
||||
eh->eh_entries = cpu_to_le16(le16_to_cpu(eh->eh_entries) - 1);
|
||||
le16_add_cpu(&eh->eh_entries, -1);
|
||||
merge_done = 1;
|
||||
WARN_ON(eh->eh_entries == 0);
|
||||
if (!eh->eh_entries)
|
||||
@ -1560,7 +1558,7 @@ has_space:
|
||||
path[depth].p_ext = nearex;
|
||||
}
|
||||
|
||||
eh->eh_entries = cpu_to_le16(le16_to_cpu(eh->eh_entries)+1);
|
||||
le16_add_cpu(&eh->eh_entries, 1);
|
||||
nearex = path[depth].p_ext;
|
||||
nearex->ee_block = newext->ee_block;
|
||||
ext4_ext_store_pblock(nearex, ext_pblock(newext));
|
||||
@ -1699,7 +1697,7 @@ static int ext4_ext_rm_idx(handle_t *handle, struct inode *inode,
|
||||
err = ext4_ext_get_access(handle, inode, path);
|
||||
if (err)
|
||||
return err;
|
||||
path->p_hdr->eh_entries = cpu_to_le16(le16_to_cpu(path->p_hdr->eh_entries)-1);
|
||||
le16_add_cpu(&path->p_hdr->eh_entries, -1);
|
||||
err = ext4_ext_dirty(handle, inode, path);
|
||||
if (err)
|
||||
return err;
|
||||
@ -1902,7 +1900,7 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode,
|
||||
if (num == 0) {
|
||||
/* this extent is removed; mark slot entirely unused */
|
||||
ext4_ext_store_pblock(ex, 0);
|
||||
eh->eh_entries = cpu_to_le16(le16_to_cpu(eh->eh_entries)-1);
|
||||
le16_add_cpu(&eh->eh_entries, -1);
|
||||
}
|
||||
|
||||
ex->ee_block = cpu_to_le32(block);
|
||||
@ -1979,7 +1977,7 @@ static int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start)
|
||||
* We start scanning from right side, freeing all the blocks
|
||||
* after i_size and walking into the tree depth-wise.
|
||||
*/
|
||||
path = kzalloc(sizeof(struct ext4_ext_path) * (depth + 1), GFP_KERNEL);
|
||||
path = kzalloc(sizeof(struct ext4_ext_path) * (depth + 1), GFP_NOFS);
|
||||
if (path == NULL) {
|
||||
ext4_journal_stop(handle);
|
||||
return -ENOMEM;
|
||||
@ -2138,6 +2136,82 @@ void ext4_ext_release(struct super_block *sb)
|
||||
#endif
|
||||
}
|
||||
|
||||
static void bi_complete(struct bio *bio, int error)
|
||||
{
|
||||
complete((struct completion *)bio->bi_private);
|
||||
}
|
||||
|
||||
/* FIXME!! we need to try to merge to left or right after zero-out */
|
||||
static int ext4_ext_zeroout(struct inode *inode, struct ext4_extent *ex)
|
||||
{
|
||||
int ret = -EIO;
|
||||
struct bio *bio;
|
||||
int blkbits, blocksize;
|
||||
sector_t ee_pblock;
|
||||
struct completion event;
|
||||
unsigned int ee_len, len, done, offset;
|
||||
|
||||
|
||||
blkbits = inode->i_blkbits;
|
||||
blocksize = inode->i_sb->s_blocksize;
|
||||
ee_len = ext4_ext_get_actual_len(ex);
|
||||
ee_pblock = ext_pblock(ex);
|
||||
|
||||
/* convert ee_pblock to 512 byte sectors */
|
||||
ee_pblock = ee_pblock << (blkbits - 9);
|
||||
|
||||
while (ee_len > 0) {
|
||||
|
||||
if (ee_len > BIO_MAX_PAGES)
|
||||
len = BIO_MAX_PAGES;
|
||||
else
|
||||
len = ee_len;
|
||||
|
||||
bio = bio_alloc(GFP_NOIO, len);
|
||||
if (!bio)
|
||||
return -ENOMEM;
|
||||
bio->bi_sector = ee_pblock;
|
||||
bio->bi_bdev = inode->i_sb->s_bdev;
|
||||
|
||||
done = 0;
|
||||
offset = 0;
|
||||
while (done < len) {
|
||||
ret = bio_add_page(bio, ZERO_PAGE(0),
|
||||
blocksize, offset);
|
||||
if (ret != blocksize) {
|
||||
/*
|
||||
* We can't add any more pages because of
|
||||
* hardware limitations. Start a new bio.
|
||||
*/
|
||||
break;
|
||||
}
|
||||
done++;
|
||||
offset += blocksize;
|
||||
if (offset >= PAGE_CACHE_SIZE)
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
init_completion(&event);
|
||||
bio->bi_private = &event;
|
||||
bio->bi_end_io = bi_complete;
|
||||
submit_bio(WRITE, bio);
|
||||
wait_for_completion(&event);
|
||||
|
||||
if (test_bit(BIO_UPTODATE, &bio->bi_flags))
|
||||
ret = 0;
|
||||
else {
|
||||
ret = -EIO;
|
||||
break;
|
||||
}
|
||||
bio_put(bio);
|
||||
ee_len -= done;
|
||||
ee_pblock += done << (blkbits - 9);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define EXT4_EXT_ZERO_LEN 7
|
||||
|
||||
/*
|
||||
* This function is called by ext4_ext_get_blocks() if someone tries to write
|
||||
* to an uninitialized extent. It may result in splitting the uninitialized
|
||||
@ -2154,7 +2228,7 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
|
||||
ext4_lblk_t iblock,
|
||||
unsigned long max_blocks)
|
||||
{
|
||||
struct ext4_extent *ex, newex;
|
||||
struct ext4_extent *ex, newex, orig_ex;
|
||||
struct ext4_extent *ex1 = NULL;
|
||||
struct ext4_extent *ex2 = NULL;
|
||||
struct ext4_extent *ex3 = NULL;
|
||||
@ -2173,10 +2247,26 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
|
||||
allocated = ee_len - (iblock - ee_block);
|
||||
newblock = iblock - ee_block + ext_pblock(ex);
|
||||
ex2 = ex;
|
||||
orig_ex.ee_block = ex->ee_block;
|
||||
orig_ex.ee_len = cpu_to_le16(ee_len);
|
||||
ext4_ext_store_pblock(&orig_ex, ext_pblock(ex));
|
||||
|
||||
err = ext4_ext_get_access(handle, inode, path + depth);
|
||||
if (err)
|
||||
goto out;
|
||||
/* If extent has less than 2*EXT4_EXT_ZERO_LEN zerout directly */
|
||||
if (ee_len <= 2*EXT4_EXT_ZERO_LEN) {
|
||||
err = ext4_ext_zeroout(inode, &orig_ex);
|
||||
if (err)
|
||||
goto fix_extent_len;
|
||||
/* update the extent length and mark as initialized */
|
||||
ex->ee_block = orig_ex.ee_block;
|
||||
ex->ee_len = orig_ex.ee_len;
|
||||
ext4_ext_store_pblock(ex, ext_pblock(&orig_ex));
|
||||
ext4_ext_dirty(handle, inode, path + depth);
|
||||
/* zeroed the full extent */
|
||||
return allocated;
|
||||
}
|
||||
|
||||
/* ex1: ee_block to iblock - 1 : uninitialized */
|
||||
if (iblock > ee_block) {
|
||||
@ -2195,19 +2285,103 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
|
||||
/* ex3: to ee_block + ee_len : uninitialised */
|
||||
if (allocated > max_blocks) {
|
||||
unsigned int newdepth;
|
||||
/* If extent has less than EXT4_EXT_ZERO_LEN zerout directly */
|
||||
if (allocated <= EXT4_EXT_ZERO_LEN) {
|
||||
/* Mark first half uninitialized.
|
||||
* Mark second half initialized and zero out the
|
||||
* initialized extent
|
||||
*/
|
||||
ex->ee_block = orig_ex.ee_block;
|
||||
ex->ee_len = cpu_to_le16(ee_len - allocated);
|
||||
ext4_ext_mark_uninitialized(ex);
|
||||
ext4_ext_store_pblock(ex, ext_pblock(&orig_ex));
|
||||
ext4_ext_dirty(handle, inode, path + depth);
|
||||
|
||||
ex3 = &newex;
|
||||
ex3->ee_block = cpu_to_le32(iblock);
|
||||
ext4_ext_store_pblock(ex3, newblock);
|
||||
ex3->ee_len = cpu_to_le16(allocated);
|
||||
err = ext4_ext_insert_extent(handle, inode, path, ex3);
|
||||
if (err == -ENOSPC) {
|
||||
err = ext4_ext_zeroout(inode, &orig_ex);
|
||||
if (err)
|
||||
goto fix_extent_len;
|
||||
ex->ee_block = orig_ex.ee_block;
|
||||
ex->ee_len = orig_ex.ee_len;
|
||||
ext4_ext_store_pblock(ex, ext_pblock(&orig_ex));
|
||||
ext4_ext_dirty(handle, inode, path + depth);
|
||||
/* zeroed the full extent */
|
||||
return allocated;
|
||||
|
||||
} else if (err)
|
||||
goto fix_extent_len;
|
||||
|
||||
/*
|
||||
* We need to zero out the second half because
|
||||
* an fallocate request can update file size and
|
||||
* converting the second half to initialized extent
|
||||
* implies that we can leak some junk data to user
|
||||
* space.
|
||||
*/
|
||||
err = ext4_ext_zeroout(inode, ex3);
|
||||
if (err) {
|
||||
/*
|
||||
* We should actually mark the
|
||||
* second half as uninit and return error
|
||||
* Insert would have changed the extent
|
||||
*/
|
||||
depth = ext_depth(inode);
|
||||
ext4_ext_drop_refs(path);
|
||||
path = ext4_ext_find_extent(inode,
|
||||
iblock, path);
|
||||
if (IS_ERR(path)) {
|
||||
err = PTR_ERR(path);
|
||||
return err;
|
||||
}
|
||||
ex = path[depth].p_ext;
|
||||
err = ext4_ext_get_access(handle, inode,
|
||||
path + depth);
|
||||
if (err)
|
||||
return err;
|
||||
ext4_ext_mark_uninitialized(ex);
|
||||
ext4_ext_dirty(handle, inode, path + depth);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* zeroed the second half */
|
||||
return allocated;
|
||||
}
|
||||
ex3 = &newex;
|
||||
ex3->ee_block = cpu_to_le32(iblock + max_blocks);
|
||||
ext4_ext_store_pblock(ex3, newblock + max_blocks);
|
||||
ex3->ee_len = cpu_to_le16(allocated - max_blocks);
|
||||
ext4_ext_mark_uninitialized(ex3);
|
||||
err = ext4_ext_insert_extent(handle, inode, path, ex3);
|
||||
if (err)
|
||||
goto out;
|
||||
if (err == -ENOSPC) {
|
||||
err = ext4_ext_zeroout(inode, &orig_ex);
|
||||
if (err)
|
||||
goto fix_extent_len;
|
||||
/* update the extent length and mark as initialized */
|
||||
ex->ee_block = orig_ex.ee_block;
|
||||
ex->ee_len = orig_ex.ee_len;
|
||||
ext4_ext_store_pblock(ex, ext_pblock(&orig_ex));
|
||||
ext4_ext_dirty(handle, inode, path + depth);
|
||||
/* zeroed the full extent */
|
||||
return allocated;
|
||||
|
||||
} else if (err)
|
||||
goto fix_extent_len;
|
||||
/*
|
||||
* The depth, and hence eh & ex might change
|
||||
* as part of the insert above.
|
||||
*/
|
||||
newdepth = ext_depth(inode);
|
||||
/*
|
||||
* update the extent length after successfull insert of the
|
||||
* split extent
|
||||
*/
|
||||
orig_ex.ee_len = cpu_to_le16(ee_len -
|
||||
ext4_ext_get_actual_len(ex3));
|
||||
if (newdepth != depth) {
|
||||
depth = newdepth;
|
||||
ext4_ext_drop_refs(path);
|
||||
@ -2226,6 +2400,24 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
|
||||
goto out;
|
||||
}
|
||||
allocated = max_blocks;
|
||||
|
||||
/* If extent has less than EXT4_EXT_ZERO_LEN and we are trying
|
||||
* to insert a extent in the middle zerout directly
|
||||
* otherwise give the extent a chance to merge to left
|
||||
*/
|
||||
if (le16_to_cpu(orig_ex.ee_len) <= EXT4_EXT_ZERO_LEN &&
|
||||
iblock != ee_block) {
|
||||
err = ext4_ext_zeroout(inode, &orig_ex);
|
||||
if (err)
|
||||
goto fix_extent_len;
|
||||
/* update the extent length and mark as initialized */
|
||||
ex->ee_block = orig_ex.ee_block;
|
||||
ex->ee_len = orig_ex.ee_len;
|
||||
ext4_ext_store_pblock(ex, ext_pblock(&orig_ex));
|
||||
ext4_ext_dirty(handle, inode, path + depth);
|
||||
/* zero out the first half */
|
||||
return allocated;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* If there was a change of depth as part of the
|
||||
@ -2282,8 +2474,29 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
|
||||
goto out;
|
||||
insert:
|
||||
err = ext4_ext_insert_extent(handle, inode, path, &newex);
|
||||
if (err == -ENOSPC) {
|
||||
err = ext4_ext_zeroout(inode, &orig_ex);
|
||||
if (err)
|
||||
goto fix_extent_len;
|
||||
/* update the extent length and mark as initialized */
|
||||
ex->ee_block = orig_ex.ee_block;
|
||||
ex->ee_len = orig_ex.ee_len;
|
||||
ext4_ext_store_pblock(ex, ext_pblock(&orig_ex));
|
||||
ext4_ext_dirty(handle, inode, path + depth);
|
||||
/* zero out the first half */
|
||||
return allocated;
|
||||
} else if (err)
|
||||
goto fix_extent_len;
|
||||
out:
|
||||
return err ? err : allocated;
|
||||
|
||||
fix_extent_len:
|
||||
ex->ee_block = orig_ex.ee_block;
|
||||
ex->ee_len = orig_ex.ee_len;
|
||||
ext4_ext_store_pblock(ex, ext_pblock(&orig_ex));
|
||||
ext4_ext_mark_uninitialized(ex);
|
||||
ext4_ext_dirty(handle, inode, path + depth);
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2393,8 +2606,20 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
|
||||
}
|
||||
if (create == EXT4_CREATE_UNINITIALIZED_EXT)
|
||||
goto out;
|
||||
if (!create)
|
||||
if (!create) {
|
||||
/*
|
||||
* We have blocks reserved already. We
|
||||
* return allocated blocks so that delalloc
|
||||
* won't do block reservation for us. But
|
||||
* the buffer head will be unmapped so that
|
||||
* a read from the block returns 0s.
|
||||
*/
|
||||
if (allocated > max_blocks)
|
||||
allocated = max_blocks;
|
||||
/* mark the buffer unwritten */
|
||||
__set_bit(BH_Unwritten, &bh_result->b_state);
|
||||
goto out2;
|
||||
}
|
||||
|
||||
ret = ext4_ext_convert_to_initialized(handle, inode,
|
||||
path, iblock,
|
||||
@ -2584,6 +2809,8 @@ out_stop:
|
||||
ext4_orphan_del(handle, inode);
|
||||
|
||||
up_write(&EXT4_I(inode)->i_data_sem);
|
||||
inode->i_mtime = inode->i_ctime = ext4_current_time(inode);
|
||||
ext4_mark_inode_dirty(handle, inode);
|
||||
ext4_journal_stop(handle);
|
||||
}
|
||||
|
||||
@ -2608,6 +2835,28 @@ int ext4_ext_writepage_trans_blocks(struct inode *inode, int num)
|
||||
return needed;
|
||||
}
|
||||
|
||||
static void ext4_falloc_update_inode(struct inode *inode,
|
||||
int mode, loff_t new_size, int update_ctime)
|
||||
{
|
||||
struct timespec now;
|
||||
|
||||
if (update_ctime) {
|
||||
now = current_fs_time(inode->i_sb);
|
||||
if (!timespec_equal(&inode->i_ctime, &now))
|
||||
inode->i_ctime = now;
|
||||
}
|
||||
/*
|
||||
* Update only when preallocation was requested beyond
|
||||
* the file size.
|
||||
*/
|
||||
if (!(mode & FALLOC_FL_KEEP_SIZE) &&
|
||||
new_size > i_size_read(inode)) {
|
||||
i_size_write(inode, new_size);
|
||||
EXT4_I(inode)->i_disksize = new_size;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* preallocate space for a file. This implements ext4's fallocate inode
|
||||
* operation, which gets called from sys_fallocate system call.
|
||||
@ -2619,8 +2868,8 @@ long ext4_fallocate(struct inode *inode, int mode, loff_t offset, loff_t len)
|
||||
{
|
||||
handle_t *handle;
|
||||
ext4_lblk_t block;
|
||||
loff_t new_size;
|
||||
unsigned long max_blocks;
|
||||
ext4_fsblk_t nblocks = 0;
|
||||
int ret = 0;
|
||||
int ret2 = 0;
|
||||
int retries = 0;
|
||||
@ -2639,9 +2888,12 @@ long ext4_fallocate(struct inode *inode, int mode, loff_t offset, loff_t len)
|
||||
return -ENODEV;
|
||||
|
||||
block = offset >> blkbits;
|
||||
/*
|
||||
* We can't just convert len to max_blocks because
|
||||
* If blocksize = 4096 offset = 3072 and len = 2048
|
||||
*/
|
||||
max_blocks = (EXT4_BLOCK_ALIGN(len + offset, blkbits) >> blkbits)
|
||||
- block;
|
||||
|
||||
- block;
|
||||
/*
|
||||
* credits to insert 1 extent into extent tree + buffers to be able to
|
||||
* modify 1 super block, 1 block bitmap and 1 group descriptor.
|
||||
@ -2657,7 +2909,6 @@ retry:
|
||||
ret = PTR_ERR(handle);
|
||||
break;
|
||||
}
|
||||
|
||||
ret = ext4_get_blocks_wrap(handle, inode, block,
|
||||
max_blocks, &map_bh,
|
||||
EXT4_CREATE_UNINITIALIZED_EXT, 0);
|
||||
@ -2673,61 +2924,24 @@ retry:
|
||||
ret2 = ext4_journal_stop(handle);
|
||||
break;
|
||||
}
|
||||
if (ret > 0) {
|
||||
/* check wrap through sign-bit/zero here */
|
||||
if ((block + ret) < 0 || (block + ret) < block) {
|
||||
ret = -EIO;
|
||||
ext4_mark_inode_dirty(handle, inode);
|
||||
ret2 = ext4_journal_stop(handle);
|
||||
break;
|
||||
}
|
||||
if (buffer_new(&map_bh) && ((block + ret) >
|
||||
(EXT4_BLOCK_ALIGN(i_size_read(inode), blkbits)
|
||||
>> blkbits)))
|
||||
nblocks = nblocks + ret;
|
||||
}
|
||||
|
||||
/* Update ctime if new blocks get allocated */
|
||||
if (nblocks) {
|
||||
struct timespec now;
|
||||
|
||||
now = current_fs_time(inode->i_sb);
|
||||
if (!timespec_equal(&inode->i_ctime, &now))
|
||||
inode->i_ctime = now;
|
||||
}
|
||||
if ((block + ret) >= (EXT4_BLOCK_ALIGN(offset + len,
|
||||
blkbits) >> blkbits))
|
||||
new_size = offset + len;
|
||||
else
|
||||
new_size = (block + ret) << blkbits;
|
||||
|
||||
ext4_falloc_update_inode(inode, mode, new_size,
|
||||
buffer_new(&map_bh));
|
||||
ext4_mark_inode_dirty(handle, inode);
|
||||
ret2 = ext4_journal_stop(handle);
|
||||
if (ret2)
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries))
|
||||
if (ret == -ENOSPC &&
|
||||
ext4_should_retry_alloc(inode->i_sb, &retries)) {
|
||||
ret = 0;
|
||||
goto retry;
|
||||
|
||||
/*
|
||||
* Time to update the file size.
|
||||
* Update only when preallocation was requested beyond the file size.
|
||||
*/
|
||||
if (!(mode & FALLOC_FL_KEEP_SIZE) &&
|
||||
(offset + len) > i_size_read(inode)) {
|
||||
if (ret > 0) {
|
||||
/*
|
||||
* if no error, we assume preallocation succeeded
|
||||
* completely
|
||||
*/
|
||||
i_size_write(inode, offset + len);
|
||||
EXT4_I(inode)->i_disksize = i_size_read(inode);
|
||||
} else if (ret < 0 && nblocks) {
|
||||
/* Handle partial allocation scenario */
|
||||
loff_t newsize;
|
||||
|
||||
newsize = (nblocks << blkbits) + i_size_read(inode);
|
||||
i_size_write(inode, EXT4_BLOCK_ALIGN(newsize, blkbits));
|
||||
EXT4_I(inode)->i_disksize = i_size_read(inode);
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&inode->i_mutex);
|
||||
return ret > 0 ? ret2 : ret;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -21,21 +21,7 @@
|
||||
* mballoc.c contains the multiblocks allocation routines
|
||||
*/
|
||||
|
||||
#include <linux/time.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/namei.h>
|
||||
#include <linux/ext4_jbd2.h>
|
||||
#include <linux/ext4_fs.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 "group.h"
|
||||
|
||||
#include "mballoc.h"
|
||||
/*
|
||||
* MUSTDO:
|
||||
* - test ext4_ext_search_left() and ext4_ext_search_right()
|
||||
@ -345,288 +331,6 @@
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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);
|
||||
ext4_fsblk_t ext4_new_blocks_old(handle_t *handle, struct inode *inode,
|
||||
ext4_fsblk_t goal, unsigned long *count, int *errp);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static inline void *mb_correct_addr_and_bit(int *bit, void *addr)
|
||||
{
|
||||
#if BITS_PER_LONG == 64
|
||||
@ -736,7 +440,7 @@ static void mb_free_blocks_double(struct inode *inode, struct ext4_buddy *e4b,
|
||||
blocknr +=
|
||||
le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block);
|
||||
|
||||
ext4_error(sb, __FUNCTION__, "double-free of inode"
|
||||
ext4_error(sb, __func__, "double-free of inode"
|
||||
" %lu's block %llu(bit %u in group %lu)\n",
|
||||
inode ? inode->i_ino : 0, blocknr,
|
||||
first + i, e4b->bd_group);
|
||||
@ -898,17 +602,17 @@ static int __mb_check_buddy(struct ext4_buddy *e4b, char *file,
|
||||
list_for_each(cur, &grp->bb_prealloc_list) {
|
||||
ext4_group_t groupnr;
|
||||
struct ext4_prealloc_space *pa;
|
||||
pa = list_entry(cur, struct ext4_prealloc_space, group_list);
|
||||
ext4_get_group_no_and_offset(sb, pa->pstart, &groupnr, &k);
|
||||
pa = list_entry(cur, struct ext4_prealloc_space, pa_group_list);
|
||||
ext4_get_group_no_and_offset(sb, pa->pa_pstart, &groupnr, &k);
|
||||
MB_CHECK_ASSERT(groupnr == e4b->bd_group);
|
||||
for (i = 0; i < pa->len; i++)
|
||||
for (i = 0; i < pa->pa_len; i++)
|
||||
MB_CHECK_ASSERT(mb_test_bit(k + i, buddy));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#undef MB_CHECK_ASSERT
|
||||
#define mb_check_buddy(e4b) __mb_check_buddy(e4b, \
|
||||
__FILE__, __FUNCTION__, __LINE__)
|
||||
__FILE__, __func__, __LINE__)
|
||||
#else
|
||||
#define mb_check_buddy(e4b)
|
||||
#endif
|
||||
@ -982,7 +686,7 @@ static void ext4_mb_generate_buddy(struct super_block *sb,
|
||||
grp->bb_fragments = fragments;
|
||||
|
||||
if (free != grp->bb_free) {
|
||||
ext4_error(sb, __FUNCTION__,
|
||||
ext4_error(sb, __func__,
|
||||
"EXT4-fs: group %lu: %u blocks in bitmap, %u in gd\n",
|
||||
group, free, grp->bb_free);
|
||||
/*
|
||||
@ -1168,8 +872,9 @@ out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int ext4_mb_load_buddy(struct super_block *sb, ext4_group_t group,
|
||||
struct ext4_buddy *e4b)
|
||||
static noinline_for_stack int
|
||||
ext4_mb_load_buddy(struct super_block *sb, ext4_group_t group,
|
||||
struct ext4_buddy *e4b)
|
||||
{
|
||||
struct ext4_sb_info *sbi = EXT4_SB(sb);
|
||||
struct inode *inode = sbi->s_buddy_cache;
|
||||
@ -1367,7 +1072,7 @@ static int mb_free_blocks(struct inode *inode, struct ext4_buddy *e4b,
|
||||
blocknr +=
|
||||
le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block);
|
||||
|
||||
ext4_error(sb, __FUNCTION__, "double-free of inode"
|
||||
ext4_error(sb, __func__, "double-free of inode"
|
||||
" %lu's block %llu(bit %u in group %lu)\n",
|
||||
inode ? inode->i_ino : 0, blocknr, block,
|
||||
e4b->bd_group);
|
||||
@ -1848,7 +1553,7 @@ static void ext4_mb_complex_scan_group(struct ext4_allocation_context *ac,
|
||||
* free blocks even though group info says we
|
||||
* we have free blocks
|
||||
*/
|
||||
ext4_error(sb, __FUNCTION__, "%d free blocks as per "
|
||||
ext4_error(sb, __func__, "%d free blocks as per "
|
||||
"group info. But bitmap says 0\n",
|
||||
free);
|
||||
break;
|
||||
@ -1857,7 +1562,7 @@ static void ext4_mb_complex_scan_group(struct ext4_allocation_context *ac,
|
||||
mb_find_extent(e4b, 0, i, ac->ac_g_ex.fe_len, &ex);
|
||||
BUG_ON(ex.fe_len <= 0);
|
||||
if (free < ex.fe_len) {
|
||||
ext4_error(sb, __FUNCTION__, "%d free blocks as per "
|
||||
ext4_error(sb, __func__, "%d free blocks as per "
|
||||
"group info. But got %d blocks\n",
|
||||
free, ex.fe_len);
|
||||
/*
|
||||
@ -1965,7 +1670,8 @@ static int ext4_mb_good_group(struct ext4_allocation_context *ac,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ext4_mb_regular_allocator(struct ext4_allocation_context *ac)
|
||||
static noinline_for_stack int
|
||||
ext4_mb_regular_allocator(struct ext4_allocation_context *ac)
|
||||
{
|
||||
ext4_group_t group;
|
||||
ext4_group_t i;
|
||||
@ -2465,7 +2171,8 @@ static void ext4_mb_history_init(struct super_block *sb)
|
||||
/* if we can't allocate history, then we simple won't use it */
|
||||
}
|
||||
|
||||
static void ext4_mb_store_history(struct ext4_allocation_context *ac)
|
||||
static noinline_for_stack void
|
||||
ext4_mb_store_history(struct ext4_allocation_context *ac)
|
||||
{
|
||||
struct ext4_sb_info *sbi = EXT4_SB(ac->ac_sb);
|
||||
struct ext4_mb_history h;
|
||||
@ -2565,13 +2272,13 @@ static int ext4_mb_init_backend(struct super_block *sb)
|
||||
meta_group_info[j] = kzalloc(len, GFP_KERNEL);
|
||||
if (meta_group_info[j] == NULL) {
|
||||
printk(KERN_ERR "EXT4-fs: can't allocate buddy mem\n");
|
||||
i--;
|
||||
goto err_freebuddy;
|
||||
}
|
||||
desc = ext4_get_group_desc(sb, i, NULL);
|
||||
if (desc == NULL) {
|
||||
printk(KERN_ERR
|
||||
"EXT4-fs: can't read descriptor %lu\n", i);
|
||||
i++;
|
||||
goto err_freebuddy;
|
||||
}
|
||||
memset(meta_group_info[j], 0, len);
|
||||
@ -2611,13 +2318,11 @@ static int ext4_mb_init_backend(struct super_block *sb)
|
||||
return 0;
|
||||
|
||||
err_freebuddy:
|
||||
while (i >= 0) {
|
||||
while (i-- > 0)
|
||||
kfree(ext4_get_group_info(sb, i));
|
||||
i--;
|
||||
}
|
||||
i = num_meta_group_infos;
|
||||
err_freemeta:
|
||||
while (--i >= 0)
|
||||
while (i-- > 0)
|
||||
kfree(sbi->s_group_info[i]);
|
||||
iput(sbi->s_buddy_cache);
|
||||
err_freesgi:
|
||||
@ -2801,7 +2506,8 @@ int ext4_mb_release(struct super_block *sb)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ext4_mb_free_committed_blocks(struct super_block *sb)
|
||||
static noinline_for_stack void
|
||||
ext4_mb_free_committed_blocks(struct super_block *sb)
|
||||
{
|
||||
struct ext4_sb_info *sbi = EXT4_SB(sb);
|
||||
int err;
|
||||
@ -3021,7 +2727,8 @@ void exit_ext4_mballoc(void)
|
||||
* Check quota and mark choosed space (ac->ac_b_ex) non-free in bitmaps
|
||||
* Returns 0 if success or error code
|
||||
*/
|
||||
static int ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac,
|
||||
static noinline_for_stack int
|
||||
ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac,
|
||||
handle_t *handle)
|
||||
{
|
||||
struct buffer_head *bitmap_bh = NULL;
|
||||
@ -3070,7 +2777,7 @@ static int ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac,
|
||||
in_range(block, ext4_inode_table(sb, gdp),
|
||||
EXT4_SB(sb)->s_itb_per_group)) {
|
||||
|
||||
ext4_error(sb, __FUNCTION__,
|
||||
ext4_error(sb, __func__,
|
||||
"Allocating block in system zone - block = %llu",
|
||||
block);
|
||||
}
|
||||
@ -3094,9 +2801,7 @@ static int ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac,
|
||||
ac->ac_b_ex.fe_group,
|
||||
gdp));
|
||||
}
|
||||
gdp->bg_free_blocks_count =
|
||||
cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count)
|
||||
- ac->ac_b_ex.fe_len);
|
||||
le16_add_cpu(&gdp->bg_free_blocks_count, -ac->ac_b_ex.fe_len);
|
||||
gdp->bg_checksum = ext4_group_desc_csum(sbi, ac->ac_b_ex.fe_group, gdp);
|
||||
spin_unlock(sb_bgl_lock(sbi, ac->ac_b_ex.fe_group));
|
||||
percpu_counter_sub(&sbi->s_freeblocks_counter, ac->ac_b_ex.fe_len);
|
||||
@ -3130,7 +2835,7 @@ static void ext4_mb_normalize_group_request(struct ext4_allocation_context *ac)
|
||||
ac->ac_g_ex.fe_len = EXT4_SB(sb)->s_stripe;
|
||||
else
|
||||
ac->ac_g_ex.fe_len = EXT4_SB(sb)->s_mb_group_prealloc;
|
||||
mb_debug("#%u: goal %lu blocks for locality group\n",
|
||||
mb_debug("#%u: goal %u blocks for locality group\n",
|
||||
current->pid, ac->ac_g_ex.fe_len);
|
||||
}
|
||||
|
||||
@ -3138,15 +2843,16 @@ static void ext4_mb_normalize_group_request(struct ext4_allocation_context *ac)
|
||||
* Normalization means making request better in terms of
|
||||
* size and alignment
|
||||
*/
|
||||
static void ext4_mb_normalize_request(struct ext4_allocation_context *ac,
|
||||
static noinline_for_stack void
|
||||
ext4_mb_normalize_request(struct ext4_allocation_context *ac,
|
||||
struct ext4_allocation_request *ar)
|
||||
{
|
||||
int bsbits, max;
|
||||
ext4_lblk_t end;
|
||||
struct list_head *cur;
|
||||
loff_t size, orig_size, start_off;
|
||||
ext4_lblk_t start, orig_start;
|
||||
struct ext4_inode_info *ei = EXT4_I(ac->ac_inode);
|
||||
struct ext4_prealloc_space *pa;
|
||||
|
||||
/* do normalize only data requests, metadata requests
|
||||
do not need preallocation */
|
||||
@ -3232,12 +2938,9 @@ static void ext4_mb_normalize_request(struct ext4_allocation_context *ac,
|
||||
|
||||
/* check we don't cross already preallocated blocks */
|
||||
rcu_read_lock();
|
||||
list_for_each_rcu(cur, &ei->i_prealloc_list) {
|
||||
struct ext4_prealloc_space *pa;
|
||||
list_for_each_entry_rcu(pa, &ei->i_prealloc_list, pa_inode_list) {
|
||||
unsigned long pa_end;
|
||||
|
||||
pa = list_entry(cur, struct ext4_prealloc_space, pa_inode_list);
|
||||
|
||||
if (pa->pa_deleted)
|
||||
continue;
|
||||
spin_lock(&pa->pa_lock);
|
||||
@ -3279,10 +2982,8 @@ static void ext4_mb_normalize_request(struct ext4_allocation_context *ac,
|
||||
|
||||
/* XXX: extra loop to check we really don't overlap preallocations */
|
||||
rcu_read_lock();
|
||||
list_for_each_rcu(cur, &ei->i_prealloc_list) {
|
||||
struct ext4_prealloc_space *pa;
|
||||
list_for_each_entry_rcu(pa, &ei->i_prealloc_list, pa_inode_list) {
|
||||
unsigned long pa_end;
|
||||
pa = list_entry(cur, struct ext4_prealloc_space, pa_inode_list);
|
||||
spin_lock(&pa->pa_lock);
|
||||
if (pa->pa_deleted == 0) {
|
||||
pa_end = pa->pa_lstart + pa->pa_len;
|
||||
@ -3374,7 +3075,7 @@ static void ext4_mb_use_inode_pa(struct ext4_allocation_context *ac,
|
||||
BUG_ON(pa->pa_free < len);
|
||||
pa->pa_free -= len;
|
||||
|
||||
mb_debug("use %llu/%lu from inode pa %p\n", start, len, pa);
|
||||
mb_debug("use %llu/%u from inode pa %p\n", start, len, pa);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -3404,12 +3105,12 @@ static void ext4_mb_use_group_pa(struct ext4_allocation_context *ac,
|
||||
/*
|
||||
* search goal blocks in preallocated space
|
||||
*/
|
||||
static int ext4_mb_use_preallocated(struct ext4_allocation_context *ac)
|
||||
static noinline_for_stack int
|
||||
ext4_mb_use_preallocated(struct ext4_allocation_context *ac)
|
||||
{
|
||||
struct ext4_inode_info *ei = EXT4_I(ac->ac_inode);
|
||||
struct ext4_locality_group *lg;
|
||||
struct ext4_prealloc_space *pa;
|
||||
struct list_head *cur;
|
||||
|
||||
/* only data can be preallocated */
|
||||
if (!(ac->ac_flags & EXT4_MB_HINT_DATA))
|
||||
@ -3417,8 +3118,7 @@ static int ext4_mb_use_preallocated(struct ext4_allocation_context *ac)
|
||||
|
||||
/* first, try per-file preallocation */
|
||||
rcu_read_lock();
|
||||
list_for_each_rcu(cur, &ei->i_prealloc_list) {
|
||||
pa = list_entry(cur, struct ext4_prealloc_space, pa_inode_list);
|
||||
list_for_each_entry_rcu(pa, &ei->i_prealloc_list, pa_inode_list) {
|
||||
|
||||
/* all fields in this condition don't change,
|
||||
* so we can skip locking for them */
|
||||
@ -3450,8 +3150,7 @@ static int ext4_mb_use_preallocated(struct ext4_allocation_context *ac)
|
||||
return 0;
|
||||
|
||||
rcu_read_lock();
|
||||
list_for_each_rcu(cur, &lg->lg_prealloc_list) {
|
||||
pa = list_entry(cur, struct ext4_prealloc_space, pa_inode_list);
|
||||
list_for_each_entry_rcu(pa, &lg->lg_prealloc_list, pa_inode_list) {
|
||||
spin_lock(&pa->pa_lock);
|
||||
if (pa->pa_deleted == 0 && pa->pa_free >= ac->ac_o_ex.fe_len) {
|
||||
atomic_inc(&pa->pa_count);
|
||||
@ -3571,7 +3270,8 @@ static void ext4_mb_put_pa(struct ext4_allocation_context *ac,
|
||||
/*
|
||||
* creates new preallocated space for given inode
|
||||
*/
|
||||
static int ext4_mb_new_inode_pa(struct ext4_allocation_context *ac)
|
||||
static noinline_for_stack int
|
||||
ext4_mb_new_inode_pa(struct ext4_allocation_context *ac)
|
||||
{
|
||||
struct super_block *sb = ac->ac_sb;
|
||||
struct ext4_prealloc_space *pa;
|
||||
@ -3658,7 +3358,8 @@ static int ext4_mb_new_inode_pa(struct ext4_allocation_context *ac)
|
||||
/*
|
||||
* creates new preallocated space for locality group inodes belongs to
|
||||
*/
|
||||
static int ext4_mb_new_group_pa(struct ext4_allocation_context *ac)
|
||||
static noinline_for_stack int
|
||||
ext4_mb_new_group_pa(struct ext4_allocation_context *ac)
|
||||
{
|
||||
struct super_block *sb = ac->ac_sb;
|
||||
struct ext4_locality_group *lg;
|
||||
@ -3731,11 +3432,11 @@ static int ext4_mb_new_preallocation(struct ext4_allocation_context *ac)
|
||||
* the caller MUST hold group/inode locks.
|
||||
* TODO: optimize the case when there are no in-core structures yet
|
||||
*/
|
||||
static int ext4_mb_release_inode_pa(struct ext4_buddy *e4b,
|
||||
struct buffer_head *bitmap_bh,
|
||||
struct ext4_prealloc_space *pa)
|
||||
static noinline_for_stack int
|
||||
ext4_mb_release_inode_pa(struct ext4_buddy *e4b, struct buffer_head *bitmap_bh,
|
||||
struct ext4_prealloc_space *pa,
|
||||
struct ext4_allocation_context *ac)
|
||||
{
|
||||
struct ext4_allocation_context *ac;
|
||||
struct super_block *sb = e4b->bd_sb;
|
||||
struct ext4_sb_info *sbi = EXT4_SB(sb);
|
||||
unsigned long end;
|
||||
@ -3751,8 +3452,6 @@ static int ext4_mb_release_inode_pa(struct ext4_buddy *e4b,
|
||||
BUG_ON(group != e4b->bd_group && pa->pa_len != 0);
|
||||
end = bit + pa->pa_len;
|
||||
|
||||
ac = kmem_cache_alloc(ext4_ac_cachep, GFP_NOFS);
|
||||
|
||||
if (ac) {
|
||||
ac->ac_sb = sb;
|
||||
ac->ac_inode = pa->pa_inode;
|
||||
@ -3789,7 +3488,7 @@ static int ext4_mb_release_inode_pa(struct ext4_buddy *e4b,
|
||||
pa, (unsigned long) pa->pa_lstart,
|
||||
(unsigned long) pa->pa_pstart,
|
||||
(unsigned long) pa->pa_len);
|
||||
ext4_error(sb, __FUNCTION__, "free %u, pa_free %u\n",
|
||||
ext4_error(sb, __func__, "free %u, pa_free %u\n",
|
||||
free, pa->pa_free);
|
||||
/*
|
||||
* pa is already deleted so we use the value obtained
|
||||
@ -3797,22 +3496,19 @@ static int ext4_mb_release_inode_pa(struct ext4_buddy *e4b,
|
||||
*/
|
||||
}
|
||||
atomic_add(free, &sbi->s_mb_discarded);
|
||||
if (ac)
|
||||
kmem_cache_free(ext4_ac_cachep, ac);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int ext4_mb_release_group_pa(struct ext4_buddy *e4b,
|
||||
struct ext4_prealloc_space *pa)
|
||||
static noinline_for_stack int
|
||||
ext4_mb_release_group_pa(struct ext4_buddy *e4b,
|
||||
struct ext4_prealloc_space *pa,
|
||||
struct ext4_allocation_context *ac)
|
||||
{
|
||||
struct ext4_allocation_context *ac;
|
||||
struct super_block *sb = e4b->bd_sb;
|
||||
ext4_group_t group;
|
||||
ext4_grpblk_t bit;
|
||||
|
||||
ac = kmem_cache_alloc(ext4_ac_cachep, GFP_NOFS);
|
||||
|
||||
if (ac)
|
||||
ac->ac_op = EXT4_MB_HISTORY_DISCARD;
|
||||
|
||||
@ -3830,7 +3526,6 @@ static int ext4_mb_release_group_pa(struct ext4_buddy *e4b,
|
||||
ac->ac_b_ex.fe_len = pa->pa_len;
|
||||
ac->ac_b_ex.fe_logical = 0;
|
||||
ext4_mb_store_history(ac);
|
||||
kmem_cache_free(ext4_ac_cachep, ac);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -3845,12 +3540,14 @@ static int ext4_mb_release_group_pa(struct ext4_buddy *e4b,
|
||||
* - how many do we discard
|
||||
* 1) how many requested
|
||||
*/
|
||||
static int ext4_mb_discard_group_preallocations(struct super_block *sb,
|
||||
static noinline_for_stack int
|
||||
ext4_mb_discard_group_preallocations(struct super_block *sb,
|
||||
ext4_group_t group, int needed)
|
||||
{
|
||||
struct ext4_group_info *grp = ext4_get_group_info(sb, group);
|
||||
struct buffer_head *bitmap_bh = NULL;
|
||||
struct ext4_prealloc_space *pa, *tmp;
|
||||
struct ext4_allocation_context *ac;
|
||||
struct list_head list;
|
||||
struct ext4_buddy e4b;
|
||||
int err;
|
||||
@ -3878,6 +3575,7 @@ static int ext4_mb_discard_group_preallocations(struct super_block *sb,
|
||||
grp = ext4_get_group_info(sb, group);
|
||||
INIT_LIST_HEAD(&list);
|
||||
|
||||
ac = kmem_cache_alloc(ext4_ac_cachep, GFP_NOFS);
|
||||
repeat:
|
||||
ext4_lock_group(sb, group);
|
||||
list_for_each_entry_safe(pa, tmp,
|
||||
@ -3932,9 +3630,9 @@ repeat:
|
||||
spin_unlock(pa->pa_obj_lock);
|
||||
|
||||
if (pa->pa_linear)
|
||||
ext4_mb_release_group_pa(&e4b, pa);
|
||||
ext4_mb_release_group_pa(&e4b, pa, ac);
|
||||
else
|
||||
ext4_mb_release_inode_pa(&e4b, bitmap_bh, pa);
|
||||
ext4_mb_release_inode_pa(&e4b, bitmap_bh, pa, ac);
|
||||
|
||||
list_del(&pa->u.pa_tmp_list);
|
||||
call_rcu(&(pa)->u.pa_rcu, ext4_mb_pa_callback);
|
||||
@ -3942,6 +3640,8 @@ repeat:
|
||||
|
||||
out:
|
||||
ext4_unlock_group(sb, group);
|
||||
if (ac)
|
||||
kmem_cache_free(ext4_ac_cachep, ac);
|
||||
ext4_mb_release_desc(&e4b);
|
||||
put_bh(bitmap_bh);
|
||||
return free;
|
||||
@ -3962,6 +3662,7 @@ void ext4_mb_discard_inode_preallocations(struct inode *inode)
|
||||
struct super_block *sb = inode->i_sb;
|
||||
struct buffer_head *bitmap_bh = NULL;
|
||||
struct ext4_prealloc_space *pa, *tmp;
|
||||
struct ext4_allocation_context *ac;
|
||||
ext4_group_t group = 0;
|
||||
struct list_head list;
|
||||
struct ext4_buddy e4b;
|
||||
@ -3976,6 +3677,7 @@ void ext4_mb_discard_inode_preallocations(struct inode *inode)
|
||||
|
||||
INIT_LIST_HEAD(&list);
|
||||
|
||||
ac = kmem_cache_alloc(ext4_ac_cachep, GFP_NOFS);
|
||||
repeat:
|
||||
/* first, collect all pa's in the inode */
|
||||
spin_lock(&ei->i_prealloc_lock);
|
||||
@ -4040,7 +3742,7 @@ repeat:
|
||||
|
||||
ext4_lock_group(sb, group);
|
||||
list_del(&pa->pa_group_list);
|
||||
ext4_mb_release_inode_pa(&e4b, bitmap_bh, pa);
|
||||
ext4_mb_release_inode_pa(&e4b, bitmap_bh, pa, ac);
|
||||
ext4_unlock_group(sb, group);
|
||||
|
||||
ext4_mb_release_desc(&e4b);
|
||||
@ -4049,6 +3751,8 @@ repeat:
|
||||
list_del(&pa->u.pa_tmp_list);
|
||||
call_rcu(&(pa)->u.pa_rcu, ext4_mb_pa_callback);
|
||||
}
|
||||
if (ac)
|
||||
kmem_cache_free(ext4_ac_cachep, ac);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -4108,7 +3812,7 @@ static void ext4_mb_show_ac(struct ext4_allocation_context *ac)
|
||||
printk(KERN_ERR "PA:%lu:%d:%u \n", i,
|
||||
start, pa->pa_len);
|
||||
}
|
||||
ext4_lock_group(sb, i);
|
||||
ext4_unlock_group(sb, i);
|
||||
|
||||
if (grp->bb_free == 0)
|
||||
continue;
|
||||
@ -4167,7 +3871,8 @@ static void ext4_mb_group_or_file(struct ext4_allocation_context *ac)
|
||||
mutex_lock(&ac->ac_lg->lg_mutex);
|
||||
}
|
||||
|
||||
static int ext4_mb_initialize_context(struct ext4_allocation_context *ac,
|
||||
static noinline_for_stack int
|
||||
ext4_mb_initialize_context(struct ext4_allocation_context *ac,
|
||||
struct ext4_allocation_request *ar)
|
||||
{
|
||||
struct super_block *sb = ar->inode->i_sb;
|
||||
@ -4398,7 +4103,8 @@ static void ext4_mb_poll_new_transaction(struct super_block *sb,
|
||||
ext4_mb_free_committed_blocks(sb);
|
||||
}
|
||||
|
||||
static int ext4_mb_free_metadata(handle_t *handle, struct ext4_buddy *e4b,
|
||||
static noinline_for_stack int
|
||||
ext4_mb_free_metadata(handle_t *handle, struct ext4_buddy *e4b,
|
||||
ext4_group_t group, ext4_grpblk_t block, int count)
|
||||
{
|
||||
struct ext4_group_info *db = e4b->bd_info;
|
||||
@ -4489,7 +4195,7 @@ void ext4_mb_free_blocks(handle_t *handle, struct inode *inode,
|
||||
if (block < le32_to_cpu(es->s_first_data_block) ||
|
||||
block + count < block ||
|
||||
block + count > ext4_blocks_count(es)) {
|
||||
ext4_error(sb, __FUNCTION__,
|
||||
ext4_error(sb, __func__,
|
||||
"Freeing blocks not in datazone - "
|
||||
"block = %lu, count = %lu", block, count);
|
||||
goto error_return;
|
||||
@ -4530,7 +4236,7 @@ do_more:
|
||||
in_range(block + count - 1, ext4_inode_table(sb, gdp),
|
||||
EXT4_SB(sb)->s_itb_per_group)) {
|
||||
|
||||
ext4_error(sb, __FUNCTION__,
|
||||
ext4_error(sb, __func__,
|
||||
"Freeing blocks in system zone - "
|
||||
"Block = %lu, count = %lu", block, count);
|
||||
}
|
||||
@ -4588,8 +4294,7 @@ do_more:
|
||||
}
|
||||
|
||||
spin_lock(sb_bgl_lock(sbi, block_group));
|
||||
gdp->bg_free_blocks_count =
|
||||
cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count) + count);
|
||||
le16_add_cpu(&gdp->bg_free_blocks_count, count);
|
||||
gdp->bg_checksum = ext4_group_desc_csum(sbi, block_group, gdp);
|
||||
spin_unlock(sb_bgl_lock(sbi, block_group));
|
||||
percpu_counter_add(&sbi->s_freeblocks_counter, count);
|
||||
|
304
fs/ext4/mballoc.h
Normal file
304
fs/ext4/mballoc.h
Normal file
@ -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
|
@ -13,8 +13,8 @@
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/ext4_jbd2.h>
|
||||
#include <linux/ext4_fs_extents.h>
|
||||
#include "ext4_jbd2.h"
|
||||
#include "ext4_extents.h"
|
||||
|
||||
/*
|
||||
* The contiguous blocks details which can be
|
||||
@ -327,7 +327,7 @@ static int free_ind_block(handle_t *handle, struct inode *inode, __le32 *i_data)
|
||||
}
|
||||
|
||||
static int ext4_ext_swap_inode_data(handle_t *handle, struct inode *inode,
|
||||
struct inode *tmp_inode)
|
||||
struct inode *tmp_inode)
|
||||
{
|
||||
int retval;
|
||||
__le32 i_data[3];
|
||||
@ -339,7 +339,7 @@ static int ext4_ext_swap_inode_data(handle_t *handle, struct inode *inode,
|
||||
* i_data field of the original inode
|
||||
*/
|
||||
retval = ext4_journal_extend(handle, 1);
|
||||
if (retval != 0) {
|
||||
if (retval) {
|
||||
retval = ext4_journal_restart(handle, 1);
|
||||
if (retval)
|
||||
goto err_out;
|
||||
@ -350,6 +350,18 @@ static int ext4_ext_swap_inode_data(handle_t *handle, struct inode *inode,
|
||||
i_data[2] = ei->i_data[EXT4_TIND_BLOCK];
|
||||
|
||||
down_write(&EXT4_I(inode)->i_data_sem);
|
||||
/*
|
||||
* if EXT4_EXT_MIGRATE is cleared a block allocation
|
||||
* happened after we started the migrate. We need to
|
||||
* fail the migrate
|
||||
*/
|
||||
if (!(EXT4_I(inode)->i_flags & EXT4_EXT_MIGRATE)) {
|
||||
retval = -EAGAIN;
|
||||
up_write(&EXT4_I(inode)->i_data_sem);
|
||||
goto err_out;
|
||||
} else
|
||||
EXT4_I(inode)->i_flags = EXT4_I(inode)->i_flags &
|
||||
~EXT4_EXT_MIGRATE;
|
||||
/*
|
||||
* We have the extent map build with the tmp inode.
|
||||
* Now copy the i_data across
|
||||
@ -508,6 +520,17 @@ int ext4_ext_migrate(struct inode *inode, struct file *filp,
|
||||
* switch the inode format to prevent read.
|
||||
*/
|
||||
mutex_lock(&(inode->i_mutex));
|
||||
/*
|
||||
* Even though we take i_mutex we can still cause block allocation
|
||||
* via mmap write to holes. If we have allocated new blocks we fail
|
||||
* migrate. New block allocation will clear EXT4_EXT_MIGRATE flag.
|
||||
* The flag is updated with i_data_sem held to prevent racing with
|
||||
* block allocation.
|
||||
*/
|
||||
down_read((&EXT4_I(inode)->i_data_sem));
|
||||
EXT4_I(inode)->i_flags = EXT4_I(inode)->i_flags | EXT4_EXT_MIGRATE;
|
||||
up_read((&EXT4_I(inode)->i_data_sem));
|
||||
|
||||
handle = ext4_journal_start(inode, 1);
|
||||
|
||||
ei = EXT4_I(inode);
|
||||
@ -559,9 +582,15 @@ err_out:
|
||||
* tmp_inode
|
||||
*/
|
||||
free_ext_block(handle, tmp_inode);
|
||||
else
|
||||
retval = ext4_ext_swap_inode_data(handle, inode,
|
||||
tmp_inode);
|
||||
else {
|
||||
retval = ext4_ext_swap_inode_data(handle, inode, tmp_inode);
|
||||
if (retval)
|
||||
/*
|
||||
* if we fail to swap inode data free the extent
|
||||
* details of the tmp inode
|
||||
*/
|
||||
free_ext_block(handle, tmp_inode);
|
||||
}
|
||||
|
||||
/* We mark the tmp_inode dirty via ext4_ext_tree_init. */
|
||||
if (ext4_journal_extend(handle, 1) != 0)
|
||||
|
@ -28,14 +28,14 @@
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/jbd2.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/ext4_fs.h>
|
||||
#include <linux/ext4_jbd2.h>
|
||||
#include <linux/fcntl.h>
|
||||
#include <linux/stat.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/quotaops.h>
|
||||
#include <linux/buffer_head.h>
|
||||
#include <linux/bio.h>
|
||||
#include "ext4.h"
|
||||
#include "ext4_jbd2.h"
|
||||
|
||||
#include "namei.h"
|
||||
#include "xattr.h"
|
||||
@ -57,10 +57,15 @@ static struct buffer_head *ext4_append(handle_t *handle,
|
||||
|
||||
*block = inode->i_size >> inode->i_sb->s_blocksize_bits;
|
||||
|
||||
if ((bh = ext4_bread(handle, inode, *block, 1, err))) {
|
||||
bh = ext4_bread(handle, inode, *block, 1, err);
|
||||
if (bh) {
|
||||
inode->i_size += inode->i_sb->s_blocksize;
|
||||
EXT4_I(inode)->i_disksize = inode->i_size;
|
||||
ext4_journal_get_write_access(handle,bh);
|
||||
*err = ext4_journal_get_write_access(handle, bh);
|
||||
if (*err) {
|
||||
brelse(bh);
|
||||
bh = NULL;
|
||||
}
|
||||
}
|
||||
return bh;
|
||||
}
|
||||
@ -348,7 +353,7 @@ dx_probe(struct dentry *dentry, struct inode *dir,
|
||||
if (root->info.hash_version != DX_HASH_TEA &&
|
||||
root->info.hash_version != DX_HASH_HALF_MD4 &&
|
||||
root->info.hash_version != DX_HASH_LEGACY) {
|
||||
ext4_warning(dir->i_sb, __FUNCTION__,
|
||||
ext4_warning(dir->i_sb, __func__,
|
||||
"Unrecognised inode hash code %d",
|
||||
root->info.hash_version);
|
||||
brelse(bh);
|
||||
@ -362,7 +367,7 @@ dx_probe(struct dentry *dentry, struct inode *dir,
|
||||
hash = hinfo->hash;
|
||||
|
||||
if (root->info.unused_flags & 1) {
|
||||
ext4_warning(dir->i_sb, __FUNCTION__,
|
||||
ext4_warning(dir->i_sb, __func__,
|
||||
"Unimplemented inode hash flags: %#06x",
|
||||
root->info.unused_flags);
|
||||
brelse(bh);
|
||||
@ -371,7 +376,7 @@ dx_probe(struct dentry *dentry, struct inode *dir,
|
||||
}
|
||||
|
||||
if ((indirect = root->info.indirect_levels) > 1) {
|
||||
ext4_warning(dir->i_sb, __FUNCTION__,
|
||||
ext4_warning(dir->i_sb, __func__,
|
||||
"Unimplemented inode hash depth: %#06x",
|
||||
root->info.indirect_levels);
|
||||
brelse(bh);
|
||||
@ -384,7 +389,7 @@ dx_probe(struct dentry *dentry, struct inode *dir,
|
||||
|
||||
if (dx_get_limit(entries) != dx_root_limit(dir,
|
||||
root->info.info_length)) {
|
||||
ext4_warning(dir->i_sb, __FUNCTION__,
|
||||
ext4_warning(dir->i_sb, __func__,
|
||||
"dx entry: limit != root limit");
|
||||
brelse(bh);
|
||||
*err = ERR_BAD_DX_DIR;
|
||||
@ -396,7 +401,7 @@ dx_probe(struct dentry *dentry, struct inode *dir,
|
||||
{
|
||||
count = dx_get_count(entries);
|
||||
if (!count || count > dx_get_limit(entries)) {
|
||||
ext4_warning(dir->i_sb, __FUNCTION__,
|
||||
ext4_warning(dir->i_sb, __func__,
|
||||
"dx entry: no count or count > limit");
|
||||
brelse(bh);
|
||||
*err = ERR_BAD_DX_DIR;
|
||||
@ -441,7 +446,7 @@ dx_probe(struct dentry *dentry, struct inode *dir,
|
||||
goto fail2;
|
||||
at = entries = ((struct dx_node *) bh->b_data)->entries;
|
||||
if (dx_get_limit(entries) != dx_node_limit (dir)) {
|
||||
ext4_warning(dir->i_sb, __FUNCTION__,
|
||||
ext4_warning(dir->i_sb, __func__,
|
||||
"dx entry: limit != node limit");
|
||||
brelse(bh);
|
||||
*err = ERR_BAD_DX_DIR;
|
||||
@ -457,7 +462,7 @@ fail2:
|
||||
}
|
||||
fail:
|
||||
if (*err == ERR_BAD_DX_DIR)
|
||||
ext4_warning(dir->i_sb, __FUNCTION__,
|
||||
ext4_warning(dir->i_sb, __func__,
|
||||
"Corrupt dir inode %ld, running e2fsck is "
|
||||
"recommended.", dir->i_ino);
|
||||
return NULL;
|
||||
@ -914,7 +919,7 @@ restart:
|
||||
wait_on_buffer(bh);
|
||||
if (!buffer_uptodate(bh)) {
|
||||
/* read error, skip block & hope for the best */
|
||||
ext4_error(sb, __FUNCTION__, "reading directory #%lu "
|
||||
ext4_error(sb, __func__, "reading directory #%lu "
|
||||
"offset %lu", dir->i_ino,
|
||||
(unsigned long)block);
|
||||
brelse(bh);
|
||||
@ -1007,7 +1012,7 @@ static struct buffer_head * ext4_dx_find_entry(struct dentry *dentry,
|
||||
retval = ext4_htree_next_block(dir, hash, frame,
|
||||
frames, NULL);
|
||||
if (retval < 0) {
|
||||
ext4_warning(sb, __FUNCTION__,
|
||||
ext4_warning(sb, __func__,
|
||||
"error reading index page in directory #%lu",
|
||||
dir->i_ino);
|
||||
*err = retval;
|
||||
@ -1532,7 +1537,7 @@ static int ext4_dx_add_entry(handle_t *handle, struct dentry *dentry,
|
||||
|
||||
if (levels && (dx_get_count(frames->entries) ==
|
||||
dx_get_limit(frames->entries))) {
|
||||
ext4_warning(sb, __FUNCTION__,
|
||||
ext4_warning(sb, __func__,
|
||||
"Directory index full!");
|
||||
err = -ENOSPC;
|
||||
goto cleanup;
|
||||
@ -1860,11 +1865,11 @@ static int empty_dir (struct inode * inode)
|
||||
if (inode->i_size < EXT4_DIR_REC_LEN(1) + EXT4_DIR_REC_LEN(2) ||
|
||||
!(bh = ext4_bread (NULL, inode, 0, 0, &err))) {
|
||||
if (err)
|
||||
ext4_error(inode->i_sb, __FUNCTION__,
|
||||
ext4_error(inode->i_sb, __func__,
|
||||
"error %d reading directory #%lu offset 0",
|
||||
err, inode->i_ino);
|
||||
else
|
||||
ext4_warning(inode->i_sb, __FUNCTION__,
|
||||
ext4_warning(inode->i_sb, __func__,
|
||||
"bad directory (dir #%lu) - no data block",
|
||||
inode->i_ino);
|
||||
return 1;
|
||||
@ -1893,7 +1898,7 @@ static int empty_dir (struct inode * inode)
|
||||
offset >> EXT4_BLOCK_SIZE_BITS(sb), 0, &err);
|
||||
if (!bh) {
|
||||
if (err)
|
||||
ext4_error(sb, __FUNCTION__,
|
||||
ext4_error(sb, __func__,
|
||||
"error %d reading directory"
|
||||
" #%lu offset %lu",
|
||||
err, inode->i_ino, offset);
|
||||
@ -2217,6 +2222,8 @@ retry:
|
||||
goto out_stop;
|
||||
}
|
||||
} else {
|
||||
/* clear the extent format for fast symlink */
|
||||
EXT4_I(inode)->i_flags &= ~EXT4_EXTENTS_FL;
|
||||
inode->i_op = &ext4_fast_symlink_inode_operations;
|
||||
memcpy((char*)&EXT4_I(inode)->i_data,symname,l);
|
||||
inode->i_size = l-1;
|
||||
@ -2347,6 +2354,9 @@ static int ext4_rename (struct inode * old_dir, struct dentry *old_dentry,
|
||||
EXT4_FEATURE_INCOMPAT_FILETYPE))
|
||||
new_de->file_type = old_de->file_type;
|
||||
new_dir->i_version++;
|
||||
new_dir->i_ctime = new_dir->i_mtime =
|
||||
ext4_current_time(new_dir);
|
||||
ext4_mark_inode_dirty(handle, new_dir);
|
||||
BUFFER_TRACE(new_bh, "call ext4_journal_dirty_metadata");
|
||||
ext4_journal_dirty_metadata(handle, new_bh);
|
||||
brelse(new_bh);
|
||||
|
@ -11,11 +11,10 @@
|
||||
|
||||
#define EXT4FS_DEBUG
|
||||
|
||||
#include <linux/ext4_jbd2.h>
|
||||
|
||||
#include <linux/errno.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "ext4_jbd2.h"
|
||||
#include "group.h"
|
||||
|
||||
#define outside(b, first, last) ((b) < (first) || (b) >= (last))
|
||||
@ -50,63 +49,63 @@ static int verify_group_input(struct super_block *sb,
|
||||
|
||||
ext4_get_group_no_and_offset(sb, start, NULL, &offset);
|
||||
if (group != sbi->s_groups_count)
|
||||
ext4_warning(sb, __FUNCTION__,
|
||||
ext4_warning(sb, __func__,
|
||||
"Cannot add at group %u (only %lu groups)",
|
||||
input->group, sbi->s_groups_count);
|
||||
else if (offset != 0)
|
||||
ext4_warning(sb, __FUNCTION__, "Last group not full");
|
||||
ext4_warning(sb, __func__, "Last group not full");
|
||||
else if (input->reserved_blocks > input->blocks_count / 5)
|
||||
ext4_warning(sb, __FUNCTION__, "Reserved blocks too high (%u)",
|
||||
ext4_warning(sb, __func__, "Reserved blocks too high (%u)",
|
||||
input->reserved_blocks);
|
||||
else if (free_blocks_count < 0)
|
||||
ext4_warning(sb, __FUNCTION__, "Bad blocks count %u",
|
||||
ext4_warning(sb, __func__, "Bad blocks count %u",
|
||||
input->blocks_count);
|
||||
else if (!(bh = sb_bread(sb, end - 1)))
|
||||
ext4_warning(sb, __FUNCTION__,
|
||||
ext4_warning(sb, __func__,
|
||||
"Cannot read last block (%llu)",
|
||||
end - 1);
|
||||
else if (outside(input->block_bitmap, start, end))
|
||||
ext4_warning(sb, __FUNCTION__,
|
||||
ext4_warning(sb, __func__,
|
||||
"Block bitmap not in group (block %llu)",
|
||||
(unsigned long long)input->block_bitmap);
|
||||
else if (outside(input->inode_bitmap, start, end))
|
||||
ext4_warning(sb, __FUNCTION__,
|
||||
ext4_warning(sb, __func__,
|
||||
"Inode bitmap not in group (block %llu)",
|
||||
(unsigned long long)input->inode_bitmap);
|
||||
else if (outside(input->inode_table, start, end) ||
|
||||
outside(itend - 1, start, end))
|
||||
ext4_warning(sb, __FUNCTION__,
|
||||
ext4_warning(sb, __func__,
|
||||
"Inode table not in group (blocks %llu-%llu)",
|
||||
(unsigned long long)input->inode_table, itend - 1);
|
||||
else if (input->inode_bitmap == input->block_bitmap)
|
||||
ext4_warning(sb, __FUNCTION__,
|
||||
ext4_warning(sb, __func__,
|
||||
"Block bitmap same as inode bitmap (%llu)",
|
||||
(unsigned long long)input->block_bitmap);
|
||||
else if (inside(input->block_bitmap, input->inode_table, itend))
|
||||
ext4_warning(sb, __FUNCTION__,
|
||||
ext4_warning(sb, __func__,
|
||||
"Block bitmap (%llu) in inode table (%llu-%llu)",
|
||||
(unsigned long long)input->block_bitmap,
|
||||
(unsigned long long)input->inode_table, itend - 1);
|
||||
else if (inside(input->inode_bitmap, input->inode_table, itend))
|
||||
ext4_warning(sb, __FUNCTION__,
|
||||
ext4_warning(sb, __func__,
|
||||
"Inode bitmap (%llu) in inode table (%llu-%llu)",
|
||||
(unsigned long long)input->inode_bitmap,
|
||||
(unsigned long long)input->inode_table, itend - 1);
|
||||
else if (inside(input->block_bitmap, start, metaend))
|
||||
ext4_warning(sb, __FUNCTION__,
|
||||
ext4_warning(sb, __func__,
|
||||
"Block bitmap (%llu) in GDT table"
|
||||
" (%llu-%llu)",
|
||||
(unsigned long long)input->block_bitmap,
|
||||
start, metaend - 1);
|
||||
else if (inside(input->inode_bitmap, start, metaend))
|
||||
ext4_warning(sb, __FUNCTION__,
|
||||
ext4_warning(sb, __func__,
|
||||
"Inode bitmap (%llu) in GDT table"
|
||||
" (%llu-%llu)",
|
||||
(unsigned long long)input->inode_bitmap,
|
||||
start, metaend - 1);
|
||||
else if (inside(input->inode_table, start, metaend) ||
|
||||
inside(itend - 1, start, metaend))
|
||||
ext4_warning(sb, __FUNCTION__,
|
||||
ext4_warning(sb, __func__,
|
||||
"Inode table (%llu-%llu) overlaps"
|
||||
"GDT table (%llu-%llu)",
|
||||
(unsigned long long)input->inode_table,
|
||||
@ -368,7 +367,7 @@ static int verify_reserved_gdb(struct super_block *sb,
|
||||
while ((grp = ext4_list_backups(sb, &three, &five, &seven)) < end) {
|
||||
if (le32_to_cpu(*p++) !=
|
||||
grp * EXT4_BLOCKS_PER_GROUP(sb) + blk){
|
||||
ext4_warning(sb, __FUNCTION__,
|
||||
ext4_warning(sb, __func__,
|
||||
"reserved GDT %llu"
|
||||
" missing grp %d (%llu)",
|
||||
blk, grp,
|
||||
@ -424,7 +423,7 @@ static int add_new_gdb(handle_t *handle, struct inode *inode,
|
||||
*/
|
||||
if (EXT4_SB(sb)->s_sbh->b_blocknr !=
|
||||
le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block)) {
|
||||
ext4_warning(sb, __FUNCTION__,
|
||||
ext4_warning(sb, __func__,
|
||||
"won't resize using backup superblock at %llu",
|
||||
(unsigned long long)EXT4_SB(sb)->s_sbh->b_blocknr);
|
||||
return -EPERM;
|
||||
@ -448,7 +447,7 @@ static int add_new_gdb(handle_t *handle, struct inode *inode,
|
||||
|
||||
data = (__le32 *)dind->b_data;
|
||||
if (le32_to_cpu(data[gdb_num % EXT4_ADDR_PER_BLOCK(sb)]) != gdblock) {
|
||||
ext4_warning(sb, __FUNCTION__,
|
||||
ext4_warning(sb, __func__,
|
||||
"new group %u GDT block %llu not reserved",
|
||||
input->group, gdblock);
|
||||
err = -EINVAL;
|
||||
@ -469,10 +468,10 @@ static int add_new_gdb(handle_t *handle, struct inode *inode,
|
||||
goto exit_dindj;
|
||||
|
||||
n_group_desc = kmalloc((gdb_num + 1) * sizeof(struct buffer_head *),
|
||||
GFP_KERNEL);
|
||||
GFP_NOFS);
|
||||
if (!n_group_desc) {
|
||||
err = -ENOMEM;
|
||||
ext4_warning (sb, __FUNCTION__,
|
||||
ext4_warning(sb, __func__,
|
||||
"not enough memory for %lu groups", gdb_num + 1);
|
||||
goto exit_inode;
|
||||
}
|
||||
@ -502,8 +501,7 @@ static int add_new_gdb(handle_t *handle, struct inode *inode,
|
||||
EXT4_SB(sb)->s_gdb_count++;
|
||||
kfree(o_group_desc);
|
||||
|
||||
es->s_reserved_gdt_blocks =
|
||||
cpu_to_le16(le16_to_cpu(es->s_reserved_gdt_blocks) - 1);
|
||||
le16_add_cpu(&es->s_reserved_gdt_blocks, -1);
|
||||
ext4_journal_dirty_metadata(handle, EXT4_SB(sb)->s_sbh);
|
||||
|
||||
return 0;
|
||||
@ -553,7 +551,7 @@ static int reserve_backup_gdb(handle_t *handle, struct inode *inode,
|
||||
int res, i;
|
||||
int err;
|
||||
|
||||
primary = kmalloc(reserved_gdb * sizeof(*primary), GFP_KERNEL);
|
||||
primary = kmalloc(reserved_gdb * sizeof(*primary), GFP_NOFS);
|
||||
if (!primary)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -571,7 +569,7 @@ static int reserve_backup_gdb(handle_t *handle, struct inode *inode,
|
||||
/* Get each reserved primary GDT block and verify it holds backups */
|
||||
for (res = 0; res < reserved_gdb; res++, blk++) {
|
||||
if (le32_to_cpu(*data) != blk) {
|
||||
ext4_warning(sb, __FUNCTION__,
|
||||
ext4_warning(sb, __func__,
|
||||
"reserved block %llu"
|
||||
" not at offset %ld",
|
||||
blk,
|
||||
@ -715,7 +713,7 @@ static void update_backups(struct super_block *sb,
|
||||
*/
|
||||
exit_err:
|
||||
if (err) {
|
||||
ext4_warning(sb, __FUNCTION__,
|
||||
ext4_warning(sb, __func__,
|
||||
"can't update backup for group %lu (err %d), "
|
||||
"forcing fsck on next reboot", group, err);
|
||||
sbi->s_mount_state &= ~EXT4_VALID_FS;
|
||||
@ -755,33 +753,33 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input)
|
||||
|
||||
if (gdb_off == 0 && !EXT4_HAS_RO_COMPAT_FEATURE(sb,
|
||||
EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER)) {
|
||||
ext4_warning(sb, __FUNCTION__,
|
||||
ext4_warning(sb, __func__,
|
||||
"Can't resize non-sparse filesystem further");
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
if (ext4_blocks_count(es) + input->blocks_count <
|
||||
ext4_blocks_count(es)) {
|
||||
ext4_warning(sb, __FUNCTION__, "blocks_count overflow\n");
|
||||
ext4_warning(sb, __func__, "blocks_count overflow\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (le32_to_cpu(es->s_inodes_count) + EXT4_INODES_PER_GROUP(sb) <
|
||||
le32_to_cpu(es->s_inodes_count)) {
|
||||
ext4_warning(sb, __FUNCTION__, "inodes_count overflow\n");
|
||||
ext4_warning(sb, __func__, "inodes_count overflow\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (reserved_gdb || gdb_off == 0) {
|
||||
if (!EXT4_HAS_COMPAT_FEATURE(sb,
|
||||
EXT4_FEATURE_COMPAT_RESIZE_INODE)){
|
||||
ext4_warning(sb, __FUNCTION__,
|
||||
ext4_warning(sb, __func__,
|
||||
"No reserved GDT blocks, can't resize");
|
||||
return -EPERM;
|
||||
}
|
||||
inode = ext4_iget(sb, EXT4_RESIZE_INO);
|
||||
if (IS_ERR(inode)) {
|
||||
ext4_warning(sb, __FUNCTION__,
|
||||
ext4_warning(sb, __func__,
|
||||
"Error opening resize inode");
|
||||
return PTR_ERR(inode);
|
||||
}
|
||||
@ -810,7 +808,7 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input)
|
||||
|
||||
lock_super(sb);
|
||||
if (input->group != sbi->s_groups_count) {
|
||||
ext4_warning(sb, __FUNCTION__,
|
||||
ext4_warning(sb, __func__,
|
||||
"multiple resizers run on filesystem!");
|
||||
err = -EBUSY;
|
||||
goto exit_journal;
|
||||
@ -877,8 +875,7 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input)
|
||||
*/
|
||||
ext4_blocks_count_set(es, ext4_blocks_count(es) +
|
||||
input->blocks_count);
|
||||
es->s_inodes_count = cpu_to_le32(le32_to_cpu(es->s_inodes_count) +
|
||||
EXT4_INODES_PER_GROUP(sb));
|
||||
le32_add_cpu(&es->s_inodes_count, EXT4_INODES_PER_GROUP(sb));
|
||||
|
||||
/*
|
||||
* We need to protect s_groups_count against other CPUs seeing
|
||||
@ -977,13 +974,13 @@ int ext4_group_extend(struct super_block *sb, struct ext4_super_block *es,
|
||||
" too large to resize to %llu blocks safely\n",
|
||||
sb->s_id, n_blocks_count);
|
||||
if (sizeof(sector_t) < 8)
|
||||
ext4_warning(sb, __FUNCTION__,
|
||||
ext4_warning(sb, __func__,
|
||||
"CONFIG_LBD not enabled\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (n_blocks_count < o_blocks_count) {
|
||||
ext4_warning(sb, __FUNCTION__,
|
||||
ext4_warning(sb, __func__,
|
||||
"can't shrink FS - resize aborted");
|
||||
return -EBUSY;
|
||||
}
|
||||
@ -992,7 +989,7 @@ int ext4_group_extend(struct super_block *sb, struct ext4_super_block *es,
|
||||
ext4_get_group_no_and_offset(sb, o_blocks_count, NULL, &last);
|
||||
|
||||
if (last == 0) {
|
||||
ext4_warning(sb, __FUNCTION__,
|
||||
ext4_warning(sb, __func__,
|
||||
"need to use ext2online to resize further");
|
||||
return -EPERM;
|
||||
}
|
||||
@ -1000,7 +997,7 @@ int ext4_group_extend(struct super_block *sb, struct ext4_super_block *es,
|
||||
add = EXT4_BLOCKS_PER_GROUP(sb) - last;
|
||||
|
||||
if (o_blocks_count + add < o_blocks_count) {
|
||||
ext4_warning(sb, __FUNCTION__, "blocks_count overflow");
|
||||
ext4_warning(sb, __func__, "blocks_count overflow");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -1008,7 +1005,7 @@ int ext4_group_extend(struct super_block *sb, struct ext4_super_block *es,
|
||||
add = n_blocks_count - o_blocks_count;
|
||||
|
||||
if (o_blocks_count + add < n_blocks_count)
|
||||
ext4_warning(sb, __FUNCTION__,
|
||||
ext4_warning(sb, __func__,
|
||||
"will only finish group (%llu"
|
||||
" blocks, %u new)",
|
||||
o_blocks_count + add, add);
|
||||
@ -1016,7 +1013,7 @@ int ext4_group_extend(struct super_block *sb, struct ext4_super_block *es,
|
||||
/* See if the device is actually as big as what was requested */
|
||||
bh = sb_bread(sb, o_blocks_count + add -1);
|
||||
if (!bh) {
|
||||
ext4_warning(sb, __FUNCTION__,
|
||||
ext4_warning(sb, __func__,
|
||||
"can't read last block, resize aborted");
|
||||
return -ENOSPC;
|
||||
}
|
||||
@ -1028,13 +1025,13 @@ int ext4_group_extend(struct super_block *sb, struct ext4_super_block *es,
|
||||
handle = ext4_journal_start_sb(sb, 3);
|
||||
if (IS_ERR(handle)) {
|
||||
err = PTR_ERR(handle);
|
||||
ext4_warning(sb, __FUNCTION__, "error %d on journal start",err);
|
||||
ext4_warning(sb, __func__, "error %d on journal start", err);
|
||||
goto exit_put;
|
||||
}
|
||||
|
||||
lock_super(sb);
|
||||
if (o_blocks_count != ext4_blocks_count(es)) {
|
||||
ext4_warning(sb, __FUNCTION__,
|
||||
ext4_warning(sb, __func__,
|
||||
"multiple resizers run on filesystem!");
|
||||
unlock_super(sb);
|
||||
ext4_journal_stop(handle);
|
||||
@ -1044,7 +1041,7 @@ int ext4_group_extend(struct super_block *sb, struct ext4_super_block *es,
|
||||
|
||||
if ((err = ext4_journal_get_write_access(handle,
|
||||
EXT4_SB(sb)->s_sbh))) {
|
||||
ext4_warning(sb, __FUNCTION__,
|
||||
ext4_warning(sb, __func__,
|
||||
"error %d on journal write access", err);
|
||||
unlock_super(sb);
|
||||
ext4_journal_stop(handle);
|
||||
|
@ -21,8 +21,6 @@
|
||||
#include <linux/fs.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/jbd2.h>
|
||||
#include <linux/ext4_fs.h>
|
||||
#include <linux/ext4_jbd2.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/blkdev.h>
|
||||
@ -38,9 +36,10 @@
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/log2.h>
|
||||
#include <linux/crc16.h>
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
#include "ext4.h"
|
||||
#include "ext4_jbd2.h"
|
||||
#include "xattr.h"
|
||||
#include "acl.h"
|
||||
#include "namei.h"
|
||||
@ -135,7 +134,7 @@ handle_t *ext4_journal_start_sb(struct super_block *sb, int nblocks)
|
||||
* take the FS itself readonly cleanly. */
|
||||
journal = EXT4_SB(sb)->s_journal;
|
||||
if (is_journal_aborted(journal)) {
|
||||
ext4_abort(sb, __FUNCTION__,
|
||||
ext4_abort(sb, __func__,
|
||||
"Detected aborted journal");
|
||||
return ERR_PTR(-EROFS);
|
||||
}
|
||||
@ -355,7 +354,7 @@ void ext4_update_dynamic_rev(struct super_block *sb)
|
||||
if (le32_to_cpu(es->s_rev_level) > EXT4_GOOD_OLD_REV)
|
||||
return;
|
||||
|
||||
ext4_warning(sb, __FUNCTION__,
|
||||
ext4_warning(sb, __func__,
|
||||
"updating to rev %d because of new feature flag, "
|
||||
"running e2fsck is recommended",
|
||||
EXT4_DYNAMIC_REV);
|
||||
@ -945,8 +944,8 @@ static match_table_t tokens = {
|
||||
{Opt_mballoc, "mballoc"},
|
||||
{Opt_nomballoc, "nomballoc"},
|
||||
{Opt_stripe, "stripe=%u"},
|
||||
{Opt_err, NULL},
|
||||
{Opt_resize, "resize"},
|
||||
{Opt_err, NULL},
|
||||
};
|
||||
|
||||
static ext4_fsblk_t get_sb_block(void **data)
|
||||
@ -1388,11 +1387,11 @@ static int ext4_setup_super(struct super_block *sb, struct ext4_super_block *es,
|
||||
* a plain journaled filesystem we can keep it set as
|
||||
* valid forever! :)
|
||||
*/
|
||||
es->s_state = cpu_to_le16(le16_to_cpu(es->s_state) & ~EXT4_VALID_FS);
|
||||
es->s_state &= cpu_to_le16(~EXT4_VALID_FS);
|
||||
#endif
|
||||
if (!(__s16) le16_to_cpu(es->s_max_mnt_count))
|
||||
es->s_max_mnt_count = cpu_to_le16(EXT4_DFL_MAX_MNT_COUNT);
|
||||
es->s_mnt_count=cpu_to_le16(le16_to_cpu(es->s_mnt_count) + 1);
|
||||
le16_add_cpu(&es->s_mnt_count, 1);
|
||||
es->s_mtime = cpu_to_le32(get_seconds());
|
||||
ext4_update_dynamic_rev(sb);
|
||||
EXT4_SET_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER);
|
||||
@ -1485,36 +1484,33 @@ static int ext4_check_descriptors(struct super_block *sb)
|
||||
block_bitmap = ext4_block_bitmap(sb, gdp);
|
||||
if (block_bitmap < first_block || block_bitmap > last_block)
|
||||
{
|
||||
ext4_error (sb, "ext4_check_descriptors",
|
||||
"Block bitmap for group %lu"
|
||||
" not in group (block %llu)!",
|
||||
i, block_bitmap);
|
||||
printk(KERN_ERR "EXT4-fs: ext4_check_descriptors: "
|
||||
"Block bitmap for group %lu not in group "
|
||||
"(block %llu)!", i, block_bitmap);
|
||||
return 0;
|
||||
}
|
||||
inode_bitmap = ext4_inode_bitmap(sb, gdp);
|
||||
if (inode_bitmap < first_block || inode_bitmap > last_block)
|
||||
{
|
||||
ext4_error (sb, "ext4_check_descriptors",
|
||||
"Inode bitmap for group %lu"
|
||||
" not in group (block %llu)!",
|
||||
i, inode_bitmap);
|
||||
printk(KERN_ERR "EXT4-fs: ext4_check_descriptors: "
|
||||
"Inode bitmap for group %lu not in group "
|
||||
"(block %llu)!", i, inode_bitmap);
|
||||
return 0;
|
||||
}
|
||||
inode_table = ext4_inode_table(sb, gdp);
|
||||
if (inode_table < first_block ||
|
||||
inode_table + sbi->s_itb_per_group - 1 > last_block)
|
||||
{
|
||||
ext4_error (sb, "ext4_check_descriptors",
|
||||
"Inode table for group %lu"
|
||||
" not in group (block %llu)!",
|
||||
i, inode_table);
|
||||
printk(KERN_ERR "EXT4-fs: ext4_check_descriptors: "
|
||||
"Inode table for group %lu not in group "
|
||||
"(block %llu)!", i, inode_table);
|
||||
return 0;
|
||||
}
|
||||
if (!ext4_group_desc_csum_verify(sbi, i, gdp)) {
|
||||
ext4_error(sb, __FUNCTION__,
|
||||
"Checksum for group %lu failed (%u!=%u)\n",
|
||||
i, le16_to_cpu(ext4_group_desc_csum(sbi, i,
|
||||
gdp)), le16_to_cpu(gdp->bg_checksum));
|
||||
printk(KERN_ERR "EXT4-fs: ext4_check_descriptors: "
|
||||
"Checksum for group %lu failed (%u!=%u)\n",
|
||||
i, le16_to_cpu(ext4_group_desc_csum(sbi, i,
|
||||
gdp)), le16_to_cpu(gdp->bg_checksum));
|
||||
return 0;
|
||||
}
|
||||
if (!flexbg_flag)
|
||||
@ -1594,8 +1590,8 @@ static void ext4_orphan_cleanup (struct super_block * sb,
|
||||
while (es->s_last_orphan) {
|
||||
struct inode *inode;
|
||||
|
||||
if (!(inode =
|
||||
ext4_orphan_get(sb, le32_to_cpu(es->s_last_orphan)))) {
|
||||
inode = ext4_orphan_get(sb, le32_to_cpu(es->s_last_orphan));
|
||||
if (IS_ERR(inode)) {
|
||||
es->s_last_orphan = 0;
|
||||
break;
|
||||
}
|
||||
@ -1605,7 +1601,7 @@ static void ext4_orphan_cleanup (struct super_block * sb,
|
||||
if (inode->i_nlink) {
|
||||
printk(KERN_DEBUG
|
||||
"%s: truncating inode %lu to %Ld bytes\n",
|
||||
__FUNCTION__, inode->i_ino, inode->i_size);
|
||||
__func__, inode->i_ino, inode->i_size);
|
||||
jbd_debug(2, "truncating inode %lu to %Ld bytes\n",
|
||||
inode->i_ino, inode->i_size);
|
||||
ext4_truncate(inode);
|
||||
@ -1613,7 +1609,7 @@ static void ext4_orphan_cleanup (struct super_block * sb,
|
||||
} else {
|
||||
printk(KERN_DEBUG
|
||||
"%s: deleting unreferenced inode %lu\n",
|
||||
__FUNCTION__, inode->i_ino);
|
||||
__func__, inode->i_ino);
|
||||
jbd_debug(2, "deleting unreferenced inode %lu\n",
|
||||
inode->i_ino);
|
||||
nr_orphans++;
|
||||
@ -2699,9 +2695,9 @@ static void ext4_clear_journal_err(struct super_block * sb,
|
||||
char nbuf[16];
|
||||
|
||||
errstr = ext4_decode_error(sb, j_errno, nbuf);
|
||||
ext4_warning(sb, __FUNCTION__, "Filesystem error recorded "
|
||||
ext4_warning(sb, __func__, "Filesystem error recorded "
|
||||
"from previous mount: %s", errstr);
|
||||
ext4_warning(sb, __FUNCTION__, "Marking fs in need of "
|
||||
ext4_warning(sb, __func__, "Marking fs in need of "
|
||||
"filesystem check.");
|
||||
|
||||
EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS;
|
||||
@ -2828,7 +2824,7 @@ static int ext4_remount (struct super_block * sb, int * flags, char * data)
|
||||
}
|
||||
|
||||
if (sbi->s_mount_opt & EXT4_MOUNT_ABORT)
|
||||
ext4_abort(sb, __FUNCTION__, "Abort forced by user");
|
||||
ext4_abort(sb, __func__, "Abort forced by user");
|
||||
|
||||
sb->s_flags = (sb->s_flags & ~MS_POSIXACL) |
|
||||
((sbi->s_mount_opt & EXT4_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0);
|
||||
@ -3040,8 +3036,14 @@ static int ext4_dquot_drop(struct inode *inode)
|
||||
|
||||
/* We may delete quota structure so we need to reserve enough blocks */
|
||||
handle = ext4_journal_start(inode, 2*EXT4_QUOTA_DEL_BLOCKS(inode->i_sb));
|
||||
if (IS_ERR(handle))
|
||||
if (IS_ERR(handle)) {
|
||||
/*
|
||||
* We call dquot_drop() anyway to at least release references
|
||||
* to quota structures so that umount does not hang.
|
||||
*/
|
||||
dquot_drop(inode);
|
||||
return PTR_ERR(handle);
|
||||
}
|
||||
ret = dquot_drop(inode);
|
||||
err = ext4_journal_stop(handle);
|
||||
if (!ret)
|
||||
|
@ -19,8 +19,8 @@
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/jbd2.h>
|
||||
#include <linux/ext4_fs.h>
|
||||
#include <linux/namei.h>
|
||||
#include "ext4.h"
|
||||
#include "xattr.h"
|
||||
|
||||
static void * ext4_follow_link(struct dentry *dentry, struct nameidata *nd)
|
||||
|
@ -53,11 +53,11 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/ext4_jbd2.h>
|
||||
#include <linux/ext4_fs.h>
|
||||
#include <linux/mbcache.h>
|
||||
#include <linux/quotaops.h>
|
||||
#include <linux/rwsem.h>
|
||||
#include "ext4_jbd2.h"
|
||||
#include "ext4.h"
|
||||
#include "xattr.h"
|
||||
#include "acl.h"
|
||||
|
||||
@ -92,6 +92,8 @@ static struct buffer_head *ext4_xattr_cache_find(struct inode *,
|
||||
struct mb_cache_entry **);
|
||||
static void ext4_xattr_rehash(struct ext4_xattr_header *,
|
||||
struct ext4_xattr_entry *);
|
||||
static int ext4_xattr_list(struct inode *inode, char *buffer,
|
||||
size_t buffer_size);
|
||||
|
||||
static struct mb_cache *ext4_xattr_cache;
|
||||
|
||||
@ -225,7 +227,7 @@ ext4_xattr_block_get(struct inode *inode, int name_index, const char *name,
|
||||
ea_bdebug(bh, "b_count=%d, refcount=%d",
|
||||
atomic_read(&(bh->b_count)), le32_to_cpu(BHDR(bh)->h_refcount));
|
||||
if (ext4_xattr_check_block(bh)) {
|
||||
bad_block: ext4_error(inode->i_sb, __FUNCTION__,
|
||||
bad_block: ext4_error(inode->i_sb, __func__,
|
||||
"inode %lu: bad block %llu", inode->i_ino,
|
||||
EXT4_I(inode)->i_file_acl);
|
||||
error = -EIO;
|
||||
@ -367,7 +369,7 @@ ext4_xattr_block_list(struct inode *inode, char *buffer, size_t buffer_size)
|
||||
ea_bdebug(bh, "b_count=%d, refcount=%d",
|
||||
atomic_read(&(bh->b_count)), le32_to_cpu(BHDR(bh)->h_refcount));
|
||||
if (ext4_xattr_check_block(bh)) {
|
||||
ext4_error(inode->i_sb, __FUNCTION__,
|
||||
ext4_error(inode->i_sb, __func__,
|
||||
"inode %lu: bad block %llu", inode->i_ino,
|
||||
EXT4_I(inode)->i_file_acl);
|
||||
error = -EIO;
|
||||
@ -420,7 +422,7 @@ cleanup:
|
||||
* Returns a negative error number on failure, or the number of bytes
|
||||
* used / required on success.
|
||||
*/
|
||||
int
|
||||
static int
|
||||
ext4_xattr_list(struct inode *inode, char *buffer, size_t buffer_size)
|
||||
{
|
||||
int i_error, b_error;
|
||||
@ -484,8 +486,7 @@ ext4_xattr_release_block(handle_t *handle, struct inode *inode,
|
||||
get_bh(bh);
|
||||
ext4_forget(handle, 1, inode, bh, bh->b_blocknr);
|
||||
} else {
|
||||
BHDR(bh)->h_refcount = cpu_to_le32(
|
||||
le32_to_cpu(BHDR(bh)->h_refcount) - 1);
|
||||
le32_add_cpu(&BHDR(bh)->h_refcount, -1);
|
||||
error = ext4_journal_dirty_metadata(handle, bh);
|
||||
if (IS_SYNC(inode))
|
||||
handle->h_sync = 1;
|
||||
@ -660,7 +661,7 @@ ext4_xattr_block_find(struct inode *inode, struct ext4_xattr_info *i,
|
||||
atomic_read(&(bs->bh->b_count)),
|
||||
le32_to_cpu(BHDR(bs->bh)->h_refcount));
|
||||
if (ext4_xattr_check_block(bs->bh)) {
|
||||
ext4_error(sb, __FUNCTION__,
|
||||
ext4_error(sb, __func__,
|
||||
"inode %lu: bad block %llu", inode->i_ino,
|
||||
EXT4_I(inode)->i_file_acl);
|
||||
error = -EIO;
|
||||
@ -738,7 +739,7 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode,
|
||||
ce = NULL;
|
||||
}
|
||||
ea_bdebug(bs->bh, "cloning");
|
||||
s->base = kmalloc(bs->bh->b_size, GFP_KERNEL);
|
||||
s->base = kmalloc(bs->bh->b_size, GFP_NOFS);
|
||||
error = -ENOMEM;
|
||||
if (s->base == NULL)
|
||||
goto cleanup;
|
||||
@ -750,7 +751,7 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode,
|
||||
}
|
||||
} else {
|
||||
/* Allocate a buffer where we construct the new block. */
|
||||
s->base = kzalloc(sb->s_blocksize, GFP_KERNEL);
|
||||
s->base = kzalloc(sb->s_blocksize, GFP_NOFS);
|
||||
/* assert(header == s->base) */
|
||||
error = -ENOMEM;
|
||||
if (s->base == NULL)
|
||||
@ -789,8 +790,7 @@ inserted:
|
||||
if (error)
|
||||
goto cleanup_dquot;
|
||||
lock_buffer(new_bh);
|
||||
BHDR(new_bh)->h_refcount = cpu_to_le32(1 +
|
||||
le32_to_cpu(BHDR(new_bh)->h_refcount));
|
||||
le32_add_cpu(&BHDR(new_bh)->h_refcount, 1);
|
||||
ea_bdebug(new_bh, "reusing; refcount now=%d",
|
||||
le32_to_cpu(BHDR(new_bh)->h_refcount));
|
||||
unlock_buffer(new_bh);
|
||||
@ -808,10 +808,8 @@ inserted:
|
||||
get_bh(new_bh);
|
||||
} else {
|
||||
/* We need to allocate a new block */
|
||||
ext4_fsblk_t goal = le32_to_cpu(
|
||||
EXT4_SB(sb)->s_es->s_first_data_block) +
|
||||
(ext4_fsblk_t)EXT4_I(inode)->i_block_group *
|
||||
EXT4_BLOCKS_PER_GROUP(sb);
|
||||
ext4_fsblk_t goal = ext4_group_first_block_no(sb,
|
||||
EXT4_I(inode)->i_block_group);
|
||||
ext4_fsblk_t block = ext4_new_block(handle, inode,
|
||||
goal, &error);
|
||||
if (error)
|
||||
@ -863,7 +861,7 @@ cleanup_dquot:
|
||||
goto cleanup;
|
||||
|
||||
bad_block:
|
||||
ext4_error(inode->i_sb, __FUNCTION__,
|
||||
ext4_error(inode->i_sb, __func__,
|
||||
"inode %lu: bad block %llu", inode->i_ino,
|
||||
EXT4_I(inode)->i_file_acl);
|
||||
goto cleanup;
|
||||
@ -1166,7 +1164,7 @@ retry:
|
||||
if (!bh)
|
||||
goto cleanup;
|
||||
if (ext4_xattr_check_block(bh)) {
|
||||
ext4_error(inode->i_sb, __FUNCTION__,
|
||||
ext4_error(inode->i_sb, __func__,
|
||||
"inode %lu: bad block %llu", inode->i_ino,
|
||||
EXT4_I(inode)->i_file_acl);
|
||||
error = -EIO;
|
||||
@ -1341,14 +1339,14 @@ ext4_xattr_delete_inode(handle_t *handle, struct inode *inode)
|
||||
goto cleanup;
|
||||
bh = sb_bread(inode->i_sb, EXT4_I(inode)->i_file_acl);
|
||||
if (!bh) {
|
||||
ext4_error(inode->i_sb, __FUNCTION__,
|
||||
ext4_error(inode->i_sb, __func__,
|
||||
"inode %lu: block %llu read error", inode->i_ino,
|
||||
EXT4_I(inode)->i_file_acl);
|
||||
goto cleanup;
|
||||
}
|
||||
if (BHDR(bh)->h_magic != cpu_to_le32(EXT4_XATTR_MAGIC) ||
|
||||
BHDR(bh)->h_blocks != cpu_to_le32(1)) {
|
||||
ext4_error(inode->i_sb, __FUNCTION__,
|
||||
ext4_error(inode->i_sb, __func__,
|
||||
"inode %lu: bad block %llu", inode->i_ino,
|
||||
EXT4_I(inode)->i_file_acl);
|
||||
goto cleanup;
|
||||
@ -1475,7 +1473,7 @@ again:
|
||||
}
|
||||
bh = sb_bread(inode->i_sb, ce->e_block);
|
||||
if (!bh) {
|
||||
ext4_error(inode->i_sb, __FUNCTION__,
|
||||
ext4_error(inode->i_sb, __func__,
|
||||
"inode %lu: block %lu read error",
|
||||
inode->i_ino, (unsigned long) ce->e_block);
|
||||
} else if (le32_to_cpu(BHDR(bh)->h_refcount) >=
|
||||
|
@ -74,7 +74,6 @@ extern struct xattr_handler ext4_xattr_security_handler;
|
||||
extern ssize_t ext4_listxattr(struct dentry *, char *, size_t);
|
||||
|
||||
extern int ext4_xattr_get(struct inode *, int, const char *, void *, size_t);
|
||||
extern int ext4_xattr_list(struct inode *, char *, size_t);
|
||||
extern int ext4_xattr_set(struct inode *, int, const char *, const void *, size_t, int);
|
||||
extern int ext4_xattr_set_handle(handle_t *, struct inode *, int, const char *, const void *, size_t, int);
|
||||
|
||||
@ -98,12 +97,6 @@ ext4_xattr_get(struct inode *inode, int name_index, const char *name,
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int
|
||||
ext4_xattr_list(struct inode *inode, void *buffer, size_t size)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int
|
||||
ext4_xattr_set(struct inode *inode, int name_index, const char *name,
|
||||
const void *value, size_t size, int flags)
|
||||
|
@ -6,9 +6,9 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/ext4_jbd2.h>
|
||||
#include <linux/ext4_fs.h>
|
||||
#include <linux/security.h>
|
||||
#include "ext4_jbd2.h"
|
||||
#include "ext4.h"
|
||||
#include "xattr.h"
|
||||
|
||||
static size_t
|
||||
|
@ -9,8 +9,8 @@
|
||||
#include <linux/string.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"
|
||||
|
||||
#define XATTR_TRUSTED_PREFIX "trusted."
|
||||
|
@ -8,8 +8,8 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/string.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"
|
||||
|
||||
#define XATTR_USER_PREFIX "user."
|
||||
|
@ -519,22 +519,6 @@ void jbd2_journal_commit_transaction(journal_t *journal)
|
||||
|
||||
jbd_debug (3, "JBD: commit phase 2\n");
|
||||
|
||||
/*
|
||||
* First, drop modified flag: all accesses to the buffers
|
||||
* will be tracked for a new trasaction only -bzzz
|
||||
*/
|
||||
spin_lock(&journal->j_list_lock);
|
||||
if (commit_transaction->t_buffers) {
|
||||
new_jh = jh = commit_transaction->t_buffers->b_tnext;
|
||||
do {
|
||||
J_ASSERT_JH(new_jh, new_jh->b_modified == 1 ||
|
||||
new_jh->b_modified == 0);
|
||||
new_jh->b_modified = 0;
|
||||
new_jh = new_jh->b_tnext;
|
||||
} while (new_jh != jh);
|
||||
}
|
||||
spin_unlock(&journal->j_list_lock);
|
||||
|
||||
/*
|
||||
* Now start flushing things to disk, in the order they appear
|
||||
* on the transaction lists. Data blocks go first.
|
||||
@ -584,6 +568,9 @@ void jbd2_journal_commit_transaction(journal_t *journal)
|
||||
stats.u.run.rs_blocks = commit_transaction->t_outstanding_credits;
|
||||
stats.u.run.rs_blocks_logged = 0;
|
||||
|
||||
J_ASSERT(commit_transaction->t_nr_buffers <=
|
||||
commit_transaction->t_outstanding_credits);
|
||||
|
||||
descriptor = NULL;
|
||||
bufs = 0;
|
||||
while (commit_transaction->t_buffers) {
|
||||
|
@ -534,7 +534,7 @@ int jbd2_log_wait_commit(journal_t *journal, tid_t tid)
|
||||
if (!tid_geq(journal->j_commit_request, tid)) {
|
||||
printk(KERN_EMERG
|
||||
"%s: error: j_commit_request=%d, tid=%d\n",
|
||||
__FUNCTION__, journal->j_commit_request, tid);
|
||||
__func__, journal->j_commit_request, tid);
|
||||
}
|
||||
spin_unlock(&journal->j_state_lock);
|
||||
#endif
|
||||
@ -599,7 +599,7 @@ int jbd2_journal_bmap(journal_t *journal, unsigned long blocknr,
|
||||
|
||||
printk(KERN_ALERT "%s: journal block not found "
|
||||
"at offset %lu on %s\n",
|
||||
__FUNCTION__,
|
||||
__func__,
|
||||
blocknr,
|
||||
bdevname(journal->j_dev, b));
|
||||
err = -EIO;
|
||||
@ -997,13 +997,14 @@ fail:
|
||||
*/
|
||||
|
||||
/**
|
||||
* journal_t * jbd2_journal_init_dev() - creates an initialises a journal structure
|
||||
* journal_t * jbd2_journal_init_dev() - creates and initialises a journal structure
|
||||
* @bdev: Block device on which to create the journal
|
||||
* @fs_dev: Device which hold journalled filesystem for this journal.
|
||||
* @start: Block nr Start of journal.
|
||||
* @len: Length of the journal in blocks.
|
||||
* @blocksize: blocksize of journalling device
|
||||
* @returns: a newly created journal_t *
|
||||
*
|
||||
* Returns: a newly created journal_t *
|
||||
*
|
||||
* jbd2_journal_init_dev creates a journal which maps a fixed contiguous
|
||||
* range of blocks on an arbitrary block device.
|
||||
@ -1027,7 +1028,7 @@ journal_t * jbd2_journal_init_dev(struct block_device *bdev,
|
||||
journal->j_wbuf = kmalloc(n * sizeof(struct buffer_head*), GFP_KERNEL);
|
||||
if (!journal->j_wbuf) {
|
||||
printk(KERN_ERR "%s: Cant allocate bhs for commit thread\n",
|
||||
__FUNCTION__);
|
||||
__func__);
|
||||
kfree(journal);
|
||||
journal = NULL;
|
||||
goto out;
|
||||
@ -1083,7 +1084,7 @@ journal_t * jbd2_journal_init_inode (struct inode *inode)
|
||||
journal->j_wbuf = kmalloc(n * sizeof(struct buffer_head*), GFP_KERNEL);
|
||||
if (!journal->j_wbuf) {
|
||||
printk(KERN_ERR "%s: Cant allocate bhs for commit thread\n",
|
||||
__FUNCTION__);
|
||||
__func__);
|
||||
kfree(journal);
|
||||
return NULL;
|
||||
}
|
||||
@ -1092,7 +1093,7 @@ journal_t * jbd2_journal_init_inode (struct inode *inode)
|
||||
/* If that failed, give up */
|
||||
if (err) {
|
||||
printk(KERN_ERR "%s: Cannnot locate journal superblock\n",
|
||||
__FUNCTION__);
|
||||
__func__);
|
||||
kfree(journal);
|
||||
return NULL;
|
||||
}
|
||||
@ -1178,7 +1179,7 @@ int jbd2_journal_create(journal_t *journal)
|
||||
*/
|
||||
printk(KERN_EMERG
|
||||
"%s: creation of journal on external device!\n",
|
||||
__FUNCTION__);
|
||||
__func__);
|
||||
BUG();
|
||||
}
|
||||
|
||||
@ -1976,9 +1977,10 @@ static int journal_init_jbd2_journal_head_cache(void)
|
||||
|
||||
static void jbd2_journal_destroy_jbd2_journal_head_cache(void)
|
||||
{
|
||||
J_ASSERT(jbd2_journal_head_cache != NULL);
|
||||
kmem_cache_destroy(jbd2_journal_head_cache);
|
||||
jbd2_journal_head_cache = NULL;
|
||||
if (jbd2_journal_head_cache) {
|
||||
kmem_cache_destroy(jbd2_journal_head_cache);
|
||||
jbd2_journal_head_cache = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1997,7 +1999,7 @@ static struct journal_head *journal_alloc_journal_head(void)
|
||||
jbd_debug(1, "out of memory for journal_head\n");
|
||||
if (time_after(jiffies, last_warning + 5*HZ)) {
|
||||
printk(KERN_NOTICE "ENOMEM in %s, retrying.\n",
|
||||
__FUNCTION__);
|
||||
__func__);
|
||||
last_warning = jiffies;
|
||||
}
|
||||
while (!ret) {
|
||||
@ -2134,13 +2136,13 @@ static void __journal_remove_journal_head(struct buffer_head *bh)
|
||||
if (jh->b_frozen_data) {
|
||||
printk(KERN_WARNING "%s: freeing "
|
||||
"b_frozen_data\n",
|
||||
__FUNCTION__);
|
||||
__func__);
|
||||
jbd2_free(jh->b_frozen_data, bh->b_size);
|
||||
}
|
||||
if (jh->b_committed_data) {
|
||||
printk(KERN_WARNING "%s: freeing "
|
||||
"b_committed_data\n",
|
||||
__FUNCTION__);
|
||||
__func__);
|
||||
jbd2_free(jh->b_committed_data, bh->b_size);
|
||||
}
|
||||
bh->b_private = NULL;
|
||||
@ -2305,10 +2307,12 @@ static int __init journal_init(void)
|
||||
BUILD_BUG_ON(sizeof(struct journal_superblock_s) != 1024);
|
||||
|
||||
ret = journal_init_caches();
|
||||
if (ret != 0)
|
||||
if (ret == 0) {
|
||||
jbd2_create_debugfs_entry();
|
||||
jbd2_create_jbd_stats_proc_entry();
|
||||
} else {
|
||||
jbd2_journal_destroy_caches();
|
||||
jbd2_create_debugfs_entry();
|
||||
jbd2_create_jbd_stats_proc_entry();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
173
fs/jbd2/revoke.c
173
fs/jbd2/revoke.c
@ -139,7 +139,7 @@ repeat:
|
||||
oom:
|
||||
if (!journal_oom_retry)
|
||||
return -ENOMEM;
|
||||
jbd_debug(1, "ENOMEM in %s, retrying\n", __FUNCTION__);
|
||||
jbd_debug(1, "ENOMEM in %s, retrying\n", __func__);
|
||||
yield();
|
||||
goto repeat;
|
||||
}
|
||||
@ -167,138 +167,121 @@ static struct jbd2_revoke_record_s *find_revoke_record(journal_t *journal,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void jbd2_journal_destroy_revoke_caches(void)
|
||||
{
|
||||
if (jbd2_revoke_record_cache) {
|
||||
kmem_cache_destroy(jbd2_revoke_record_cache);
|
||||
jbd2_revoke_record_cache = NULL;
|
||||
}
|
||||
if (jbd2_revoke_table_cache) {
|
||||
kmem_cache_destroy(jbd2_revoke_table_cache);
|
||||
jbd2_revoke_table_cache = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int __init jbd2_journal_init_revoke_caches(void)
|
||||
{
|
||||
J_ASSERT(!jbd2_revoke_record_cache);
|
||||
J_ASSERT(!jbd2_revoke_table_cache);
|
||||
|
||||
jbd2_revoke_record_cache = kmem_cache_create("jbd2_revoke_record",
|
||||
sizeof(struct jbd2_revoke_record_s),
|
||||
0,
|
||||
SLAB_HWCACHE_ALIGN|SLAB_TEMPORARY,
|
||||
NULL);
|
||||
if (!jbd2_revoke_record_cache)
|
||||
return -ENOMEM;
|
||||
goto record_cache_failure;
|
||||
|
||||
jbd2_revoke_table_cache = kmem_cache_create("jbd2_revoke_table",
|
||||
sizeof(struct jbd2_revoke_table_s),
|
||||
0, SLAB_TEMPORARY, NULL);
|
||||
if (!jbd2_revoke_table_cache) {
|
||||
kmem_cache_destroy(jbd2_revoke_record_cache);
|
||||
jbd2_revoke_record_cache = NULL;
|
||||
return -ENOMEM;
|
||||
}
|
||||
if (!jbd2_revoke_table_cache)
|
||||
goto table_cache_failure;
|
||||
return 0;
|
||||
table_cache_failure:
|
||||
jbd2_journal_destroy_revoke_caches();
|
||||
record_cache_failure:
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
void jbd2_journal_destroy_revoke_caches(void)
|
||||
static struct jbd2_revoke_table_s *jbd2_journal_init_revoke_table(int hash_size)
|
||||
{
|
||||
kmem_cache_destroy(jbd2_revoke_record_cache);
|
||||
jbd2_revoke_record_cache = NULL;
|
||||
kmem_cache_destroy(jbd2_revoke_table_cache);
|
||||
jbd2_revoke_table_cache = NULL;
|
||||
}
|
||||
int shift = 0;
|
||||
int tmp = hash_size;
|
||||
struct jbd2_revoke_table_s *table;
|
||||
|
||||
/* Initialise the revoke table for a given journal to a given size. */
|
||||
table = kmem_cache_alloc(jbd2_revoke_table_cache, GFP_KERNEL);
|
||||
if (!table)
|
||||
goto out;
|
||||
|
||||
int jbd2_journal_init_revoke(journal_t *journal, int hash_size)
|
||||
{
|
||||
int shift, tmp;
|
||||
|
||||
J_ASSERT (journal->j_revoke_table[0] == NULL);
|
||||
|
||||
shift = 0;
|
||||
tmp = hash_size;
|
||||
while((tmp >>= 1UL) != 0UL)
|
||||
shift++;
|
||||
|
||||
journal->j_revoke_table[0] = kmem_cache_alloc(jbd2_revoke_table_cache, GFP_KERNEL);
|
||||
if (!journal->j_revoke_table[0])
|
||||
return -ENOMEM;
|
||||
journal->j_revoke = journal->j_revoke_table[0];
|
||||
|
||||
/* Check that the hash_size is a power of two */
|
||||
J_ASSERT(is_power_of_2(hash_size));
|
||||
|
||||
journal->j_revoke->hash_size = hash_size;
|
||||
|
||||
journal->j_revoke->hash_shift = shift;
|
||||
|
||||
journal->j_revoke->hash_table =
|
||||
table->hash_size = hash_size;
|
||||
table->hash_shift = shift;
|
||||
table->hash_table =
|
||||
kmalloc(hash_size * sizeof(struct list_head), GFP_KERNEL);
|
||||
if (!journal->j_revoke->hash_table) {
|
||||
kmem_cache_free(jbd2_revoke_table_cache, journal->j_revoke_table[0]);
|
||||
journal->j_revoke = NULL;
|
||||
return -ENOMEM;
|
||||
if (!table->hash_table) {
|
||||
kmem_cache_free(jbd2_revoke_table_cache, table);
|
||||
table = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (tmp = 0; tmp < hash_size; tmp++)
|
||||
INIT_LIST_HEAD(&journal->j_revoke->hash_table[tmp]);
|
||||
INIT_LIST_HEAD(&table->hash_table[tmp]);
|
||||
|
||||
journal->j_revoke_table[1] = kmem_cache_alloc(jbd2_revoke_table_cache, GFP_KERNEL);
|
||||
if (!journal->j_revoke_table[1]) {
|
||||
kfree(journal->j_revoke_table[0]->hash_table);
|
||||
kmem_cache_free(jbd2_revoke_table_cache, journal->j_revoke_table[0]);
|
||||
return -ENOMEM;
|
||||
out:
|
||||
return table;
|
||||
}
|
||||
|
||||
static void jbd2_journal_destroy_revoke_table(struct jbd2_revoke_table_s *table)
|
||||
{
|
||||
int i;
|
||||
struct list_head *hash_list;
|
||||
|
||||
for (i = 0; i < table->hash_size; i++) {
|
||||
hash_list = &table->hash_table[i];
|
||||
J_ASSERT(list_empty(hash_list));
|
||||
}
|
||||
|
||||
kfree(table->hash_table);
|
||||
kmem_cache_free(jbd2_revoke_table_cache, table);
|
||||
}
|
||||
|
||||
/* Initialise the revoke table for a given journal to a given size. */
|
||||
int jbd2_journal_init_revoke(journal_t *journal, int hash_size)
|
||||
{
|
||||
J_ASSERT(journal->j_revoke_table[0] == NULL);
|
||||
J_ASSERT(is_power_of_2(hash_size));
|
||||
|
||||
journal->j_revoke_table[0] = jbd2_journal_init_revoke_table(hash_size);
|
||||
if (!journal->j_revoke_table[0])
|
||||
goto fail0;
|
||||
|
||||
journal->j_revoke_table[1] = jbd2_journal_init_revoke_table(hash_size);
|
||||
if (!journal->j_revoke_table[1])
|
||||
goto fail1;
|
||||
|
||||
journal->j_revoke = journal->j_revoke_table[1];
|
||||
|
||||
/* Check that the hash_size is a power of two */
|
||||
J_ASSERT(is_power_of_2(hash_size));
|
||||
|
||||
journal->j_revoke->hash_size = hash_size;
|
||||
|
||||
journal->j_revoke->hash_shift = shift;
|
||||
|
||||
journal->j_revoke->hash_table =
|
||||
kmalloc(hash_size * sizeof(struct list_head), GFP_KERNEL);
|
||||
if (!journal->j_revoke->hash_table) {
|
||||
kfree(journal->j_revoke_table[0]->hash_table);
|
||||
kmem_cache_free(jbd2_revoke_table_cache, journal->j_revoke_table[0]);
|
||||
kmem_cache_free(jbd2_revoke_table_cache, journal->j_revoke_table[1]);
|
||||
journal->j_revoke = NULL;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
for (tmp = 0; tmp < hash_size; tmp++)
|
||||
INIT_LIST_HEAD(&journal->j_revoke->hash_table[tmp]);
|
||||
|
||||
spin_lock_init(&journal->j_revoke_lock);
|
||||
|
||||
return 0;
|
||||
|
||||
fail1:
|
||||
jbd2_journal_destroy_revoke_table(journal->j_revoke_table[0]);
|
||||
fail0:
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Destoy a journal's revoke table. The table must already be empty! */
|
||||
|
||||
/* Destroy a journal's revoke table. The table must already be empty! */
|
||||
void jbd2_journal_destroy_revoke(journal_t *journal)
|
||||
{
|
||||
struct jbd2_revoke_table_s *table;
|
||||
struct list_head *hash_list;
|
||||
int i;
|
||||
|
||||
table = journal->j_revoke_table[0];
|
||||
if (!table)
|
||||
return;
|
||||
|
||||
for (i=0; i<table->hash_size; i++) {
|
||||
hash_list = &table->hash_table[i];
|
||||
J_ASSERT (list_empty(hash_list));
|
||||
}
|
||||
|
||||
kfree(table->hash_table);
|
||||
kmem_cache_free(jbd2_revoke_table_cache, table);
|
||||
journal->j_revoke = NULL;
|
||||
|
||||
table = journal->j_revoke_table[1];
|
||||
if (!table)
|
||||
return;
|
||||
|
||||
for (i=0; i<table->hash_size; i++) {
|
||||
hash_list = &table->hash_table[i];
|
||||
J_ASSERT (list_empty(hash_list));
|
||||
}
|
||||
|
||||
kfree(table->hash_table);
|
||||
kmem_cache_free(jbd2_revoke_table_cache, table);
|
||||
journal->j_revoke = NULL;
|
||||
if (journal->j_revoke_table[0])
|
||||
jbd2_journal_destroy_revoke_table(journal->j_revoke_table[0]);
|
||||
if (journal->j_revoke_table[1])
|
||||
jbd2_journal_destroy_revoke_table(journal->j_revoke_table[1]);
|
||||
}
|
||||
|
||||
|
||||
|
@ -617,6 +617,12 @@ repeat:
|
||||
jh->b_next_transaction == transaction)
|
||||
goto done;
|
||||
|
||||
/*
|
||||
* this is the first time this transaction is touching this buffer,
|
||||
* reset the modified flag
|
||||
*/
|
||||
jh->b_modified = 0;
|
||||
|
||||
/*
|
||||
* If there is already a copy-out version of this buffer, then we don't
|
||||
* need to make another one
|
||||
@ -690,7 +696,7 @@ repeat:
|
||||
if (!frozen_buffer) {
|
||||
printk(KERN_EMERG
|
||||
"%s: OOM for frozen_buffer\n",
|
||||
__FUNCTION__);
|
||||
__func__);
|
||||
JBUFFER_TRACE(jh, "oom!");
|
||||
error = -ENOMEM;
|
||||
jbd_lock_bh_state(bh);
|
||||
@ -829,9 +835,16 @@ int jbd2_journal_get_create_access(handle_t *handle, struct buffer_head *bh)
|
||||
|
||||
if (jh->b_transaction == NULL) {
|
||||
jh->b_transaction = transaction;
|
||||
|
||||
/* first access by this transaction */
|
||||
jh->b_modified = 0;
|
||||
|
||||
JBUFFER_TRACE(jh, "file as BJ_Reserved");
|
||||
__jbd2_journal_file_buffer(jh, transaction, BJ_Reserved);
|
||||
} else if (jh->b_transaction == journal->j_committing_transaction) {
|
||||
/* first access by this transaction */
|
||||
jh->b_modified = 0;
|
||||
|
||||
JBUFFER_TRACE(jh, "set next transaction");
|
||||
jh->b_next_transaction = transaction;
|
||||
}
|
||||
@ -901,7 +914,7 @@ repeat:
|
||||
committed_data = jbd2_alloc(jh2bh(jh)->b_size, GFP_NOFS);
|
||||
if (!committed_data) {
|
||||
printk(KERN_EMERG "%s: No memory for committed data\n",
|
||||
__FUNCTION__);
|
||||
__func__);
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
@ -1230,6 +1243,7 @@ int jbd2_journal_forget (handle_t *handle, struct buffer_head *bh)
|
||||
struct journal_head *jh;
|
||||
int drop_reserve = 0;
|
||||
int err = 0;
|
||||
int was_modified = 0;
|
||||
|
||||
BUFFER_TRACE(bh, "entry");
|
||||
|
||||
@ -1248,6 +1262,9 @@ int jbd2_journal_forget (handle_t *handle, struct buffer_head *bh)
|
||||
goto not_jbd;
|
||||
}
|
||||
|
||||
/* keep track of wether or not this transaction modified us */
|
||||
was_modified = jh->b_modified;
|
||||
|
||||
/*
|
||||
* The buffer's going from the transaction, we must drop
|
||||
* all references -bzzz
|
||||
@ -1265,7 +1282,12 @@ int jbd2_journal_forget (handle_t *handle, struct buffer_head *bh)
|
||||
|
||||
JBUFFER_TRACE(jh, "belongs to current transaction: unfile");
|
||||
|
||||
drop_reserve = 1;
|
||||
/*
|
||||
* we only want to drop a reference if this transaction
|
||||
* modified the buffer
|
||||
*/
|
||||
if (was_modified)
|
||||
drop_reserve = 1;
|
||||
|
||||
/*
|
||||
* We are no longer going to journal this buffer.
|
||||
@ -1305,7 +1327,13 @@ int jbd2_journal_forget (handle_t *handle, struct buffer_head *bh)
|
||||
if (jh->b_next_transaction) {
|
||||
J_ASSERT(jh->b_next_transaction == transaction);
|
||||
jh->b_next_transaction = NULL;
|
||||
drop_reserve = 1;
|
||||
|
||||
/*
|
||||
* only drop a reference if this transaction modified
|
||||
* the buffer
|
||||
*/
|
||||
if (was_modified)
|
||||
drop_reserve = 1;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1434,7 +1462,8 @@ int jbd2_journal_stop(handle_t *handle)
|
||||
return err;
|
||||
}
|
||||
|
||||
/**int jbd2_journal_force_commit() - force any uncommitted transactions
|
||||
/**
|
||||
* int jbd2_journal_force_commit() - force any uncommitted transactions
|
||||
* @journal: journal to force
|
||||
*
|
||||
* For synchronous operations: force any uncommitted transactions
|
||||
@ -2077,7 +2106,7 @@ void __jbd2_journal_refile_buffer(struct journal_head *jh)
|
||||
jh->b_transaction = jh->b_next_transaction;
|
||||
jh->b_next_transaction = NULL;
|
||||
__jbd2_journal_file_buffer(jh, jh->b_transaction,
|
||||
was_dirty ? BJ_Metadata : BJ_Reserved);
|
||||
jh->b_modified ? BJ_Metadata : BJ_Reserved);
|
||||
J_ASSERT_JH(jh, jh->b_transaction->t_state == T_RUNNING);
|
||||
|
||||
if (was_dirty)
|
||||
|
Loading…
Reference in New Issue
Block a user