mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-07-23 23:32:14 +00:00
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4
* 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4: (40 commits) ext4: Adding error check after calling ext4_mb_regular_allocator() ext4: Fix dirtying of journalled buffers in data=journal mode ext4: re-inline ext4_rec_len_(to|from)_disk functions jbd2: Remove t_handle_lock from start_this_handle() jbd2: Change j_state_lock to be a rwlock_t jbd2: Use atomic variables to avoid taking t_handle_lock in jbd2_journal_stop ext4: Add mount options in superblock ext4: force block allocation on quota_off ext4: fix freeze deadlock under IO ext4: drop inode from orphan list if ext4_delete_inode() fails ext4: check to make make sure bd_dev is set before dereferencing it jbd2: Make barrier messages less scary ext4: don't print scary messages for allocation failures post-abort ext4: fix EFBIG edge case when writing to large non-extent file ext4: fix ext4_get_blocks references ext4: Always journal quota file modifications ext4: Fix potential memory leak in ext4_fill_super ext4: Don't error out the fs if the user tries to make a file too big ext4: allocate stripe-multiple IOs on stripe boundaries ext4: move aio completion after unwritten extent conversion ... Fix up conflicts in fs/ext4/inode.c as per Ted. Fix up xfs conflicts as per earlier xfs merge.
This commit is contained in:
commit
09dc942c2a
26 changed files with 917 additions and 654 deletions
|
@ -204,6 +204,7 @@ ext4_set_acl(handle_t *handle, struct inode *inode, int type,
|
|||
return error;
|
||||
else {
|
||||
inode->i_mode = mode;
|
||||
inode->i_ctime = ext4_current_time(inode);
|
||||
ext4_mark_inode_dirty(handle, inode);
|
||||
if (error == 0)
|
||||
acl = NULL;
|
||||
|
|
|
@ -377,14 +377,11 @@ void ext4_add_groupblocks(handle_t *handle, struct super_block *sb,
|
|||
ext4_grpblk_t bit;
|
||||
unsigned int i;
|
||||
struct ext4_group_desc *desc;
|
||||
struct ext4_super_block *es;
|
||||
struct ext4_sb_info *sbi;
|
||||
struct ext4_sb_info *sbi = EXT4_SB(sb);
|
||||
int err = 0, ret, blk_free_count;
|
||||
ext4_grpblk_t blocks_freed;
|
||||
struct ext4_group_info *grp;
|
||||
|
||||
sbi = EXT4_SB(sb);
|
||||
es = sbi->s_es;
|
||||
ext4_debug("Adding block(s) %llu-%llu\n", block, block + count - 1);
|
||||
|
||||
ext4_get_group_no_and_offset(sb, block, &block_group, &bit);
|
||||
|
@ -477,7 +474,6 @@ void ext4_add_groupblocks(handle_t *handle, struct super_block *sb,
|
|||
ret = ext4_handle_dirty_metadata(handle, NULL, gd_bh);
|
||||
if (!err)
|
||||
err = ret;
|
||||
sb->s_dirt = 1;
|
||||
|
||||
error_return:
|
||||
brelse(bitmap_bh);
|
||||
|
|
|
@ -229,16 +229,20 @@ int ext4_data_block_valid(struct ext4_sb_info *sbi, ext4_fsblk_t start_blk,
|
|||
|
||||
if ((start_blk <= le32_to_cpu(sbi->s_es->s_first_data_block)) ||
|
||||
(start_blk + count < start_blk) ||
|
||||
(start_blk + count > ext4_blocks_count(sbi->s_es)))
|
||||
(start_blk + count > ext4_blocks_count(sbi->s_es))) {
|
||||
sbi->s_es->s_last_error_block = cpu_to_le64(start_blk);
|
||||
return 0;
|
||||
}
|
||||
while (n) {
|
||||
entry = rb_entry(n, struct ext4_system_zone, node);
|
||||
if (start_blk + count - 1 < entry->start_blk)
|
||||
n = n->rb_left;
|
||||
else if (start_blk >= (entry->start_blk + entry->count))
|
||||
n = n->rb_right;
|
||||
else
|
||||
else {
|
||||
sbi->s_es->s_last_error_block = cpu_to_le64(start_blk);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -61,10 +61,11 @@ static unsigned char get_dtype(struct super_block *sb, int filetype)
|
|||
}
|
||||
|
||||
|
||||
int ext4_check_dir_entry(const char *function, struct inode *dir,
|
||||
struct ext4_dir_entry_2 *de,
|
||||
struct buffer_head *bh,
|
||||
unsigned int offset)
|
||||
int __ext4_check_dir_entry(const char *function, unsigned int line,
|
||||
struct inode *dir,
|
||||
struct ext4_dir_entry_2 *de,
|
||||
struct buffer_head *bh,
|
||||
unsigned int offset)
|
||||
{
|
||||
const char *error_msg = NULL;
|
||||
const int rlen = ext4_rec_len_from_disk(de->rec_len,
|
||||
|
@ -83,11 +84,10 @@ int ext4_check_dir_entry(const char *function, struct inode *dir,
|
|||
error_msg = "inode out of bounds";
|
||||
|
||||
if (error_msg != NULL)
|
||||
ext4_error_inode(function, dir,
|
||||
"bad entry in directory: %s - block=%llu"
|
||||
ext4_error_inode(dir, function, line, bh->b_blocknr,
|
||||
"bad entry in directory: %s - "
|
||||
"offset=%u(%u), inode=%u, rec_len=%d, name_len=%d",
|
||||
error_msg, (unsigned long long) bh->b_blocknr,
|
||||
(unsigned) (offset%bh->b_size), offset,
|
||||
error_msg, (unsigned) (offset%bh->b_size), offset,
|
||||
le32_to_cpu(de->inode),
|
||||
rlen, de->name_len);
|
||||
return error_msg == NULL ? 1 : 0;
|
||||
|
@ -121,7 +121,8 @@ static int ext4_readdir(struct file *filp,
|
|||
* We don't set the inode dirty flag since it's not
|
||||
* critical that it get flushed back to the disk.
|
||||
*/
|
||||
ext4_clear_inode_flag(filp->f_path.dentry->d_inode, EXT4_INODE_INDEX);
|
||||
ext4_clear_inode_flag(filp->f_path.dentry->d_inode,
|
||||
EXT4_INODE_INDEX);
|
||||
}
|
||||
stored = 0;
|
||||
offset = filp->f_pos & (sb->s_blocksize - 1);
|
||||
|
@ -193,7 +194,7 @@ revalidate:
|
|||
while (!error && filp->f_pos < inode->i_size
|
||||
&& offset < sb->s_blocksize) {
|
||||
de = (struct ext4_dir_entry_2 *) (bh->b_data + offset);
|
||||
if (!ext4_check_dir_entry("ext4_readdir", inode, de,
|
||||
if (!ext4_check_dir_entry(inode, de,
|
||||
bh, offset)) {
|
||||
/*
|
||||
* On error, skip the f_pos to the next block
|
||||
|
@ -343,7 +344,7 @@ int ext4_htree_store_dirent(struct file *dir_file, __u32 hash,
|
|||
struct dir_private_info *info;
|
||||
int len;
|
||||
|
||||
info = (struct dir_private_info *) dir_file->private_data;
|
||||
info = dir_file->private_data;
|
||||
p = &info->root.rb_node;
|
||||
|
||||
/* Create and allocate the fname structure */
|
||||
|
|
152
fs/ext4/ext4.h
152
fs/ext4/ext4.h
|
@ -57,10 +57,13 @@
|
|||
#endif
|
||||
|
||||
#define EXT4_ERROR_INODE(inode, fmt, a...) \
|
||||
ext4_error_inode(__func__, (inode), (fmt), ## a)
|
||||
ext4_error_inode((inode), __func__, __LINE__, 0, (fmt), ## a)
|
||||
|
||||
#define EXT4_ERROR_INODE_BLOCK(inode, block, fmt, a...) \
|
||||
ext4_error_inode((inode), __func__, __LINE__, (block), (fmt), ## a)
|
||||
|
||||
#define EXT4_ERROR_FILE(file, fmt, a...) \
|
||||
ext4_error_file(__func__, (file), (fmt), ## a)
|
||||
ext4_error_file(__func__, __LINE__, (file), (fmt), ## a)
|
||||
|
||||
/* data type for block offset of block group */
|
||||
typedef int ext4_grpblk_t;
|
||||
|
@ -167,13 +170,15 @@ struct mpage_da_data {
|
|||
};
|
||||
#define EXT4_IO_UNWRITTEN 0x1
|
||||
typedef struct ext4_io_end {
|
||||
struct list_head list; /* per-file finished AIO list */
|
||||
struct list_head list; /* per-file finished IO list */
|
||||
struct inode *inode; /* file being written to */
|
||||
unsigned int flag; /* unwritten or not */
|
||||
struct page *page; /* page struct for buffer write */
|
||||
loff_t offset; /* offset in the file */
|
||||
ssize_t size; /* size of the extent */
|
||||
struct work_struct work; /* data work queue */
|
||||
struct kiocb *iocb; /* iocb struct for AIO */
|
||||
int result; /* error value for AIO */
|
||||
} ext4_io_end_t;
|
||||
|
||||
/*
|
||||
|
@ -460,7 +465,7 @@ struct ext4_new_group_data {
|
|||
};
|
||||
|
||||
/*
|
||||
* Flags used by ext4_get_blocks()
|
||||
* Flags used by ext4_map_blocks()
|
||||
*/
|
||||
/* Allocate any needed blocks and/or convert an unitialized
|
||||
extent to be an initialized ext4 */
|
||||
|
@ -873,7 +878,6 @@ struct ext4_inode_info {
|
|||
#define EXT4_MOUNT_POSIX_ACL 0x08000 /* POSIX Access Control Lists */
|
||||
#define EXT4_MOUNT_NO_AUTO_DA_ALLOC 0x10000 /* No auto delalloc mapping */
|
||||
#define EXT4_MOUNT_BARRIER 0x20000 /* Use block barriers */
|
||||
#define EXT4_MOUNT_NOBH 0x40000 /* No bufferheads */
|
||||
#define EXT4_MOUNT_QUOTA 0x80000 /* Some quota option set */
|
||||
#define EXT4_MOUNT_USRQUOTA 0x100000 /* "old" user quota */
|
||||
#define EXT4_MOUNT_GRPQUOTA 0x200000 /* "old" group quota */
|
||||
|
@ -982,7 +986,7 @@ struct ext4_super_block {
|
|||
__le32 s_last_orphan; /* start of list of inodes to delete */
|
||||
__le32 s_hash_seed[4]; /* HTREE hash seed */
|
||||
__u8 s_def_hash_version; /* Default hash version to use */
|
||||
__u8 s_reserved_char_pad;
|
||||
__u8 s_jnl_backup_type;
|
||||
__le16 s_desc_size; /* size of group descriptor */
|
||||
/*100*/ __le32 s_default_mount_opts;
|
||||
__le32 s_first_meta_bg; /* First metablock block group */
|
||||
|
@ -1000,12 +1004,34 @@ struct ext4_super_block {
|
|||
__le64 s_mmp_block; /* Block for multi-mount protection */
|
||||
__le32 s_raid_stripe_width; /* blocks on all data disks (N*stride)*/
|
||||
__u8 s_log_groups_per_flex; /* FLEX_BG group size */
|
||||
__u8 s_reserved_char_pad2;
|
||||
__u8 s_reserved_char_pad;
|
||||
__le16 s_reserved_pad;
|
||||
__le64 s_kbytes_written; /* nr of lifetime kilobytes written */
|
||||
__u32 s_reserved[160]; /* Padding to the end of the block */
|
||||
__le32 s_snapshot_inum; /* Inode number of active snapshot */
|
||||
__le32 s_snapshot_id; /* sequential ID of active snapshot */
|
||||
__le64 s_snapshot_r_blocks_count; /* reserved blocks for active
|
||||
snapshot's future use */
|
||||
__le32 s_snapshot_list; /* inode number of the head of the
|
||||
on-disk snapshot list */
|
||||
#define EXT4_S_ERR_START offsetof(struct ext4_super_block, s_error_count)
|
||||
__le32 s_error_count; /* number of fs errors */
|
||||
__le32 s_first_error_time; /* first time an error happened */
|
||||
__le32 s_first_error_ino; /* inode involved in first error */
|
||||
__le64 s_first_error_block; /* block involved of first error */
|
||||
__u8 s_first_error_func[32]; /* function where the error happened */
|
||||
__le32 s_first_error_line; /* line number where error happened */
|
||||
__le32 s_last_error_time; /* most recent time of an error */
|
||||
__le32 s_last_error_ino; /* inode involved in last error */
|
||||
__le32 s_last_error_line; /* line number where error happened */
|
||||
__le64 s_last_error_block; /* block involved of last error */
|
||||
__u8 s_last_error_func[32]; /* function where the error happened */
|
||||
#define EXT4_S_ERR_END offsetof(struct ext4_super_block, s_mount_opts)
|
||||
__u8 s_mount_opts[64];
|
||||
__le32 s_reserved[112]; /* Padding to the end of the block */
|
||||
};
|
||||
|
||||
#define EXT4_S_ERR_LEN (EXT4_S_ERR_END - EXT4_S_ERR_START)
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
/*
|
||||
|
@ -1143,6 +1169,9 @@ struct ext4_sb_info {
|
|||
|
||||
/* workqueue for dio unwritten */
|
||||
struct workqueue_struct *dio_unwritten_wq;
|
||||
|
||||
/* timer for periodic error stats printing */
|
||||
struct timer_list s_err_report;
|
||||
};
|
||||
|
||||
static inline struct ext4_sb_info *EXT4_SB(struct super_block *sb)
|
||||
|
@ -1313,6 +1342,10 @@ EXT4_INODE_BIT_FNS(state, state_flags)
|
|||
#define EXT4_DEFM_JMODE_DATA 0x0020
|
||||
#define EXT4_DEFM_JMODE_ORDERED 0x0040
|
||||
#define EXT4_DEFM_JMODE_WBACK 0x0060
|
||||
#define EXT4_DEFM_NOBARRIER 0x0100
|
||||
#define EXT4_DEFM_BLOCK_VALIDITY 0x0200
|
||||
#define EXT4_DEFM_DISCARD 0x0400
|
||||
#define EXT4_DEFM_NODELALLOC 0x0800
|
||||
|
||||
/*
|
||||
* Default journal batch times
|
||||
|
@ -1378,6 +1411,43 @@ struct ext4_dir_entry_2 {
|
|||
~EXT4_DIR_ROUND)
|
||||
#define EXT4_MAX_REC_LEN ((1<<16)-1)
|
||||
|
||||
/*
|
||||
* If we ever get support for fs block sizes > page_size, we'll need
|
||||
* to remove the #if statements in the next two functions...
|
||||
*/
|
||||
static inline unsigned int
|
||||
ext4_rec_len_from_disk(__le16 dlen, unsigned blocksize)
|
||||
{
|
||||
unsigned len = le16_to_cpu(dlen);
|
||||
|
||||
#if (PAGE_CACHE_SIZE >= 65536)
|
||||
if (len == EXT4_MAX_REC_LEN || len == 0)
|
||||
return blocksize;
|
||||
return (len & 65532) | ((len & 3) << 16);
|
||||
#else
|
||||
return len;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline __le16 ext4_rec_len_to_disk(unsigned len, unsigned blocksize)
|
||||
{
|
||||
if ((len > blocksize) || (blocksize > (1 << 18)) || (len & 3))
|
||||
BUG();
|
||||
#if (PAGE_CACHE_SIZE >= 65536)
|
||||
if (len < 65536)
|
||||
return cpu_to_le16(len);
|
||||
if (len == blocksize) {
|
||||
if (blocksize == 65536)
|
||||
return cpu_to_le16(EXT4_MAX_REC_LEN);
|
||||
else
|
||||
return cpu_to_le16(0);
|
||||
}
|
||||
return cpu_to_le16((len & 65532) | ((len >> 16) & 3));
|
||||
#else
|
||||
return cpu_to_le16(len);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Hash Tree Directory indexing
|
||||
* (c) Daniel Phillips, 2001
|
||||
|
@ -1510,9 +1580,11 @@ extern unsigned ext4_init_block_bitmap(struct super_block *sb,
|
|||
ext4_init_block_bitmap(sb, NULL, group, desc)
|
||||
|
||||
/* dir.c */
|
||||
extern int ext4_check_dir_entry(const char *, struct inode *,
|
||||
struct ext4_dir_entry_2 *,
|
||||
struct buffer_head *, unsigned int);
|
||||
extern int __ext4_check_dir_entry(const char *, unsigned int, struct inode *,
|
||||
struct ext4_dir_entry_2 *,
|
||||
struct buffer_head *, unsigned int);
|
||||
#define ext4_check_dir_entry(dir, de, bh, offset) \
|
||||
__ext4_check_dir_entry(__func__, __LINE__, (dir), (de), (bh), (offset))
|
||||
extern int ext4_htree_store_dirent(struct file *dir_file, __u32 hash,
|
||||
__u32 minor_hash,
|
||||
struct ext4_dir_entry_2 *dirent);
|
||||
|
@ -1601,8 +1673,6 @@ extern long ext4_compat_ioctl(struct file *, unsigned int, unsigned long);
|
|||
extern int ext4_ext_migrate(struct inode *);
|
||||
|
||||
/* namei.c */
|
||||
extern unsigned int ext4_rec_len_from_disk(__le16 dlen, unsigned blocksize);
|
||||
extern __le16 ext4_rec_len_to_disk(unsigned len, unsigned blocksize);
|
||||
extern int ext4_orphan_add(handle_t *, struct inode *);
|
||||
extern int ext4_orphan_del(handle_t *, struct inode *);
|
||||
extern int ext4_htree_fill_tree(struct file *dir_file, __u32 start_hash,
|
||||
|
@ -1616,25 +1686,38 @@ extern int ext4_group_extend(struct super_block *sb,
|
|||
ext4_fsblk_t n_blocks_count);
|
||||
|
||||
/* super.c */
|
||||
extern void __ext4_error(struct super_block *, const char *, const char *, ...)
|
||||
__attribute__ ((format (printf, 3, 4)));
|
||||
#define ext4_error(sb, message...) __ext4_error(sb, __func__, ## message)
|
||||
extern void ext4_error_inode(const char *, struct inode *, const char *, ...)
|
||||
__attribute__ ((format (printf, 3, 4)));
|
||||
extern void ext4_error_file(const char *, struct file *, const char *, ...)
|
||||
__attribute__ ((format (printf, 3, 4)));
|
||||
extern void __ext4_std_error(struct super_block *, const char *, int);
|
||||
extern void ext4_abort(struct super_block *, const char *, const char *, ...)
|
||||
__attribute__ ((format (printf, 3, 4)));
|
||||
extern void __ext4_warning(struct super_block *, const char *,
|
||||
extern void __ext4_error(struct super_block *, const char *, unsigned int,
|
||||
const char *, ...)
|
||||
__attribute__ ((format (printf, 4, 5)));
|
||||
#define ext4_error(sb, message...) __ext4_error(sb, __func__, \
|
||||
__LINE__, ## message)
|
||||
extern void ext4_error_inode(struct inode *, const char *, unsigned int,
|
||||
ext4_fsblk_t, const char *, ...)
|
||||
__attribute__ ((format (printf, 5, 6)));
|
||||
extern void ext4_error_file(struct file *, const char *, unsigned int,
|
||||
const char *, ...)
|
||||
__attribute__ ((format (printf, 4, 5)));
|
||||
extern void __ext4_std_error(struct super_block *, const char *,
|
||||
unsigned int, int);
|
||||
extern void __ext4_abort(struct super_block *, const char *, unsigned int,
|
||||
const char *, ...)
|
||||
__attribute__ ((format (printf, 4, 5)));
|
||||
#define ext4_abort(sb, message...) __ext4_abort(sb, __func__, \
|
||||
__LINE__, ## message)
|
||||
extern void __ext4_warning(struct super_block *, const char *, unsigned int,
|
||||
const char *, ...)
|
||||
__attribute__ ((format (printf, 3, 4)));
|
||||
#define ext4_warning(sb, message...) __ext4_warning(sb, __func__, ## message)
|
||||
__attribute__ ((format (printf, 4, 5)));
|
||||
#define ext4_warning(sb, message...) __ext4_warning(sb, __func__, \
|
||||
__LINE__, ## message)
|
||||
extern void ext4_msg(struct super_block *, const char *, const char *, ...)
|
||||
__attribute__ ((format (printf, 3, 4)));
|
||||
extern void ext4_grp_locked_error(struct super_block *, ext4_group_t,
|
||||
const char *, const char *, ...)
|
||||
__attribute__ ((format (printf, 4, 5)));
|
||||
extern void __ext4_grp_locked_error(const char *, unsigned int, \
|
||||
struct super_block *, ext4_group_t, \
|
||||
unsigned long, ext4_fsblk_t, \
|
||||
const char *, ...)
|
||||
__attribute__ ((format (printf, 7, 8)));
|
||||
#define ext4_grp_locked_error(sb, grp, message...) \
|
||||
__ext4_grp_locked_error(__func__, __LINE__, (sb), (grp), ## message)
|
||||
extern void ext4_update_dynamic_rev(struct super_block *sb);
|
||||
extern int ext4_update_compat_feature(handle_t *handle, struct super_block *sb,
|
||||
__u32 compat);
|
||||
|
@ -1768,7 +1851,7 @@ static inline unsigned int ext4_flex_bg_size(struct ext4_sb_info *sbi)
|
|||
#define ext4_std_error(sb, errno) \
|
||||
do { \
|
||||
if ((errno)) \
|
||||
__ext4_std_error((sb), __func__, (errno)); \
|
||||
__ext4_std_error((sb), __func__, __LINE__, (errno)); \
|
||||
} while (0)
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
|
@ -1860,6 +1943,12 @@ static inline void ext4_unlock_group(struct super_block *sb,
|
|||
spin_unlock(ext4_group_lock_ptr(sb, group));
|
||||
}
|
||||
|
||||
static inline void ext4_mark_super_dirty(struct super_block *sb)
|
||||
{
|
||||
if (EXT4_SB(sb)->s_journal == NULL)
|
||||
sb->s_dirt =1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Inodes and files operations
|
||||
*/
|
||||
|
@ -1905,9 +1994,6 @@ extern int ext4_convert_unwritten_extents(struct inode *inode, loff_t offset,
|
|||
ssize_t len);
|
||||
extern int ext4_map_blocks(handle_t *handle, struct inode *inode,
|
||||
struct ext4_map_blocks *map, int flags);
|
||||
extern int ext4_get_blocks(handle_t *handle, struct inode *inode,
|
||||
sector_t block, unsigned int max_blocks,
|
||||
struct buffer_head *bh, int flags);
|
||||
extern int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
|
||||
__u64 start, __u64 len);
|
||||
/* move_extent.c */
|
||||
|
|
|
@ -6,29 +6,29 @@
|
|||
|
||||
#include <trace/events/ext4.h>
|
||||
|
||||
int __ext4_journal_get_undo_access(const char *where, handle_t *handle,
|
||||
struct buffer_head *bh)
|
||||
int __ext4_journal_get_undo_access(const char *where, unsigned int line,
|
||||
handle_t *handle, struct buffer_head *bh)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
if (ext4_handle_valid(handle)) {
|
||||
err = jbd2_journal_get_undo_access(handle, bh);
|
||||
if (err)
|
||||
ext4_journal_abort_handle(where, __func__, bh,
|
||||
ext4_journal_abort_handle(where, line, __func__, bh,
|
||||
handle, err);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
int __ext4_journal_get_write_access(const char *where, handle_t *handle,
|
||||
struct buffer_head *bh)
|
||||
int __ext4_journal_get_write_access(const char *where, unsigned int line,
|
||||
handle_t *handle, struct buffer_head *bh)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
if (ext4_handle_valid(handle)) {
|
||||
err = jbd2_journal_get_write_access(handle, bh);
|
||||
if (err)
|
||||
ext4_journal_abort_handle(where, __func__, bh,
|
||||
ext4_journal_abort_handle(where, line, __func__, bh,
|
||||
handle, err);
|
||||
}
|
||||
return err;
|
||||
|
@ -46,9 +46,9 @@ int __ext4_journal_get_write_access(const char *where, handle_t *handle,
|
|||
* If the handle isn't valid we're not journaling, but we still need to
|
||||
* call into ext4_journal_revoke() to put the buffer head.
|
||||
*/
|
||||
int __ext4_forget(const char *where, handle_t *handle, int is_metadata,
|
||||
struct inode *inode, struct buffer_head *bh,
|
||||
ext4_fsblk_t blocknr)
|
||||
int __ext4_forget(const char *where, unsigned int line, handle_t *handle,
|
||||
int is_metadata, struct inode *inode,
|
||||
struct buffer_head *bh, ext4_fsblk_t blocknr)
|
||||
{
|
||||
int err;
|
||||
|
||||
|
@ -79,8 +79,8 @@ int __ext4_forget(const char *where, handle_t *handle, int is_metadata,
|
|||
BUFFER_TRACE(bh, "call jbd2_journal_forget");
|
||||
err = jbd2_journal_forget(handle, bh);
|
||||
if (err)
|
||||
ext4_journal_abort_handle(where, __func__, bh,
|
||||
handle, err);
|
||||
ext4_journal_abort_handle(where, line, __func__,
|
||||
bh, handle, err);
|
||||
return err;
|
||||
}
|
||||
return 0;
|
||||
|
@ -92,15 +92,16 @@ int __ext4_forget(const char *where, handle_t *handle, int is_metadata,
|
|||
BUFFER_TRACE(bh, "call jbd2_journal_revoke");
|
||||
err = jbd2_journal_revoke(handle, blocknr, bh);
|
||||
if (err) {
|
||||
ext4_journal_abort_handle(where, __func__, bh, handle, err);
|
||||
ext4_abort(inode->i_sb, __func__,
|
||||
ext4_journal_abort_handle(where, line, __func__,
|
||||
bh, handle, err);
|
||||
__ext4_abort(inode->i_sb, where, line,
|
||||
"error %d when attempting revoke", err);
|
||||
}
|
||||
BUFFER_TRACE(bh, "exit");
|
||||
return err;
|
||||
}
|
||||
|
||||
int __ext4_journal_get_create_access(const char *where,
|
||||
int __ext4_journal_get_create_access(const char *where, unsigned int line,
|
||||
handle_t *handle, struct buffer_head *bh)
|
||||
{
|
||||
int err = 0;
|
||||
|
@ -108,22 +109,23 @@ int __ext4_journal_get_create_access(const char *where,
|
|||
if (ext4_handle_valid(handle)) {
|
||||
err = jbd2_journal_get_create_access(handle, bh);
|
||||
if (err)
|
||||
ext4_journal_abort_handle(where, __func__, bh,
|
||||
handle, err);
|
||||
ext4_journal_abort_handle(where, line, __func__,
|
||||
bh, handle, err);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
int __ext4_handle_dirty_metadata(const char *where, handle_t *handle,
|
||||
struct inode *inode, struct buffer_head *bh)
|
||||
int __ext4_handle_dirty_metadata(const char *where, unsigned int line,
|
||||
handle_t *handle, struct inode *inode,
|
||||
struct buffer_head *bh)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
if (ext4_handle_valid(handle)) {
|
||||
err = jbd2_journal_dirty_metadata(handle, bh);
|
||||
if (err)
|
||||
ext4_journal_abort_handle(where, __func__, bh,
|
||||
handle, err);
|
||||
ext4_journal_abort_handle(where, line, __func__,
|
||||
bh, handle, err);
|
||||
} else {
|
||||
if (inode)
|
||||
mark_buffer_dirty_inode(bh, inode);
|
||||
|
@ -132,14 +134,33 @@ int __ext4_handle_dirty_metadata(const char *where, handle_t *handle,
|
|||
if (inode && inode_needs_sync(inode)) {
|
||||
sync_dirty_buffer(bh);
|
||||
if (buffer_req(bh) && !buffer_uptodate(bh)) {
|
||||
ext4_error(inode->i_sb,
|
||||
"IO error syncing inode, "
|
||||
"inode=%lu, block=%llu",
|
||||
inode->i_ino,
|
||||
(unsigned long long) bh->b_blocknr);
|
||||
struct ext4_super_block *es;
|
||||
|
||||
es = EXT4_SB(inode->i_sb)->s_es;
|
||||
es->s_last_error_block =
|
||||
cpu_to_le64(bh->b_blocknr);
|
||||
ext4_error_inode(inode, where, line,
|
||||
bh->b_blocknr,
|
||||
"IO error syncing itable block");
|
||||
err = -EIO;
|
||||
}
|
||||
}
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
int __ext4_handle_dirty_super(const char *where, unsigned int line,
|
||||
handle_t *handle, struct super_block *sb)
|
||||
{
|
||||
struct buffer_head *bh = EXT4_SB(sb)->s_sbh;
|
||||
int err = 0;
|
||||
|
||||
if (ext4_handle_valid(handle)) {
|
||||
err = jbd2_journal_dirty_metadata(handle, bh);
|
||||
if (err)
|
||||
ext4_journal_abort_handle(where, line, __func__,
|
||||
bh, handle, err);
|
||||
} else
|
||||
sb->s_dirt = 1;
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -122,39 +122,47 @@ int ext4_mark_inode_dirty(handle_t *handle, struct inode *inode);
|
|||
/*
|
||||
* Wrapper functions with which ext4 calls into JBD.
|
||||
*/
|
||||
void ext4_journal_abort_handle(const char *caller, const char *err_fn,
|
||||
void ext4_journal_abort_handle(const char *caller, unsigned int line,
|
||||
const char *err_fn,
|
||||
struct buffer_head *bh, handle_t *handle, int err);
|
||||
|
||||
int __ext4_journal_get_undo_access(const char *where, handle_t *handle,
|
||||
struct buffer_head *bh);
|
||||
int __ext4_journal_get_undo_access(const char *where, unsigned int line,
|
||||
handle_t *handle, struct buffer_head *bh);
|
||||
|
||||
int __ext4_journal_get_write_access(const char *where, handle_t *handle,
|
||||
struct buffer_head *bh);
|
||||
int __ext4_journal_get_write_access(const char *where, unsigned int line,
|
||||
handle_t *handle, struct buffer_head *bh);
|
||||
|
||||
int __ext4_forget(const char *where, handle_t *handle, int is_metadata,
|
||||
struct inode *inode, struct buffer_head *bh,
|
||||
ext4_fsblk_t blocknr);
|
||||
int __ext4_forget(const char *where, unsigned int line, handle_t *handle,
|
||||
int is_metadata, struct inode *inode,
|
||||
struct buffer_head *bh, ext4_fsblk_t blocknr);
|
||||
|
||||
int __ext4_journal_get_create_access(const char *where,
|
||||
int __ext4_journal_get_create_access(const char *where, unsigned int line,
|
||||
handle_t *handle, struct buffer_head *bh);
|
||||
|
||||
int __ext4_handle_dirty_metadata(const char *where, handle_t *handle,
|
||||
struct inode *inode, struct buffer_head *bh);
|
||||
int __ext4_handle_dirty_metadata(const char *where, unsigned int line,
|
||||
handle_t *handle, struct inode *inode,
|
||||
struct buffer_head *bh);
|
||||
|
||||
int __ext4_handle_dirty_super(const char *where, unsigned int line,
|
||||
handle_t *handle, struct super_block *sb);
|
||||
|
||||
#define ext4_journal_get_undo_access(handle, bh) \
|
||||
__ext4_journal_get_undo_access(__func__, (handle), (bh))
|
||||
__ext4_journal_get_undo_access(__func__, __LINE__, (handle), (bh))
|
||||
#define ext4_journal_get_write_access(handle, bh) \
|
||||
__ext4_journal_get_write_access(__func__, (handle), (bh))
|
||||
__ext4_journal_get_write_access(__func__, __LINE__, (handle), (bh))
|
||||
#define ext4_forget(handle, is_metadata, inode, bh, block_nr) \
|
||||
__ext4_forget(__func__, (handle), (is_metadata), (inode), (bh),\
|
||||
(block_nr))
|
||||
__ext4_forget(__func__, __LINE__, (handle), (is_metadata), (inode), \
|
||||
(bh), (block_nr))
|
||||
#define ext4_journal_get_create_access(handle, bh) \
|
||||
__ext4_journal_get_create_access(__func__, (handle), (bh))
|
||||
__ext4_journal_get_create_access(__func__, __LINE__, (handle), (bh))
|
||||
#define ext4_handle_dirty_metadata(handle, inode, bh) \
|
||||
__ext4_handle_dirty_metadata(__func__, (handle), (inode), (bh))
|
||||
__ext4_handle_dirty_metadata(__func__, __LINE__, (handle), (inode), \
|
||||
(bh))
|
||||
#define ext4_handle_dirty_super(handle, sb) \
|
||||
__ext4_handle_dirty_super(__func__, __LINE__, (handle), (sb))
|
||||
|
||||
handle_t *ext4_journal_start_sb(struct super_block *sb, int nblocks);
|
||||
int __ext4_journal_stop(const char *where, handle_t *handle);
|
||||
int __ext4_journal_stop(const char *where, unsigned int line, handle_t *handle);
|
||||
|
||||
#define EXT4_NOJOURNAL_MAX_REF_COUNT ((unsigned long) 4096)
|
||||
|
||||
|
@ -207,7 +215,7 @@ static inline handle_t *ext4_journal_start(struct inode *inode, int nblocks)
|
|||
}
|
||||
|
||||
#define ext4_journal_stop(handle) \
|
||||
__ext4_journal_stop(__func__, (handle))
|
||||
__ext4_journal_stop(__func__, __LINE__, (handle))
|
||||
|
||||
static inline handle_t *ext4_journal_current_handle(void)
|
||||
{
|
||||
|
@ -308,17 +316,15 @@ static inline int ext4_should_writeback_data(struct inode *inode)
|
|||
* This function controls whether or not we should try to go down the
|
||||
* dioread_nolock code paths, which makes it safe to avoid taking
|
||||
* i_mutex for direct I/O reads. This only works for extent-based
|
||||
* files, and it doesn't work for nobh or if data journaling is
|
||||
* enabled, since the dioread_nolock code uses b_private to pass
|
||||
* information back to the I/O completion handler, and this conflicts
|
||||
* with the jbd's use of b_private.
|
||||
* files, and it doesn't work if data journaling is enabled, since the
|
||||
* dioread_nolock code uses b_private to pass information back to the
|
||||
* I/O completion handler, and this conflicts with the jbd's use of
|
||||
* b_private.
|
||||
*/
|
||||
static inline int ext4_should_dioread_nolock(struct inode *inode)
|
||||
{
|
||||
if (!test_opt(inode->i_sb, DIOREAD_NOLOCK))
|
||||
return 0;
|
||||
if (test_opt(inode->i_sb, NOBH))
|
||||
return 0;
|
||||
if (!S_ISREG(inode->i_mode))
|
||||
return 0;
|
||||
if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)))
|
||||
|
|
|
@ -401,9 +401,9 @@ static int ext4_valid_extent_entries(struct inode *inode,
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int __ext4_ext_check(const char *function, struct inode *inode,
|
||||
struct ext4_extent_header *eh,
|
||||
int depth)
|
||||
static int __ext4_ext_check(const char *function, unsigned int line,
|
||||
struct inode *inode, struct ext4_extent_header *eh,
|
||||
int depth)
|
||||
{
|
||||
const char *error_msg;
|
||||
int max = 0;
|
||||
|
@ -436,7 +436,7 @@ static int __ext4_ext_check(const char *function, struct inode *inode,
|
|||
return 0;
|
||||
|
||||
corrupted:
|
||||
ext4_error_inode(function, inode,
|
||||
ext4_error_inode(inode, function, line, 0,
|
||||
"bad header/extent: %s - magic %x, "
|
||||
"entries %u, max %u(%u), depth %u(%u)",
|
||||
error_msg, le16_to_cpu(eh->eh_magic),
|
||||
|
@ -447,7 +447,7 @@ corrupted:
|
|||
}
|
||||
|
||||
#define ext4_ext_check(inode, eh, depth) \
|
||||
__ext4_ext_check(__func__, inode, eh, depth)
|
||||
__ext4_ext_check(__func__, __LINE__, inode, eh, depth)
|
||||
|
||||
int ext4_ext_check_inode(struct inode *inode)
|
||||
{
|
||||
|
@ -1083,7 +1083,6 @@ static int ext4_ext_grow_indepth(handle_t *handle, struct inode *inode,
|
|||
{
|
||||
struct ext4_ext_path *curp = path;
|
||||
struct ext4_extent_header *neh;
|
||||
struct ext4_extent_idx *fidx;
|
||||
struct buffer_head *bh;
|
||||
ext4_fsblk_t newblock;
|
||||
int err = 0;
|
||||
|
@ -1144,10 +1143,10 @@ static int ext4_ext_grow_indepth(handle_t *handle, struct inode *inode,
|
|||
ext4_idx_store_pblock(curp->p_idx, newblock);
|
||||
|
||||
neh = ext_inode_hdr(inode);
|
||||
fidx = EXT_FIRST_INDEX(neh);
|
||||
ext_debug("new root: num %d(%d), lblock %d, ptr %llu\n",
|
||||
le16_to_cpu(neh->eh_entries), le16_to_cpu(neh->eh_max),
|
||||
le32_to_cpu(fidx->ei_block), idx_pblock(fidx));
|
||||
le32_to_cpu(EXT_FIRST_INDEX(neh)->ei_block),
|
||||
idx_pblock(EXT_FIRST_INDEX(neh)));
|
||||
|
||||
neh->eh_depth = cpu_to_le16(path->p_depth + 1);
|
||||
err = ext4_ext_dirty(handle, inode, curp);
|
||||
|
@ -2954,7 +2953,6 @@ static int ext4_split_unwritten_extents(handle_t *handle,
|
|||
struct ext4_extent *ex1 = NULL;
|
||||
struct ext4_extent *ex2 = NULL;
|
||||
struct ext4_extent *ex3 = NULL;
|
||||
struct ext4_extent_header *eh;
|
||||
ext4_lblk_t ee_block, eof_block;
|
||||
unsigned int allocated, ee_len, depth;
|
||||
ext4_fsblk_t newblock;
|
||||
|
@ -2971,7 +2969,6 @@ static int ext4_split_unwritten_extents(handle_t *handle,
|
|||
eof_block = map->m_lblk + map->m_len;
|
||||
|
||||
depth = ext_depth(inode);
|
||||
eh = path[depth].p_hdr;
|
||||
ex = path[depth].p_ext;
|
||||
ee_block = le32_to_cpu(ex->ee_block);
|
||||
ee_len = ext4_ext_get_actual_len(ex);
|
||||
|
@ -3058,7 +3055,6 @@ static int ext4_split_unwritten_extents(handle_t *handle,
|
|||
err = PTR_ERR(path);
|
||||
goto out;
|
||||
}
|
||||
eh = path[depth].p_hdr;
|
||||
ex = path[depth].p_ext;
|
||||
if (ex2 != &newex)
|
||||
ex2 = ex;
|
||||
|
|
|
@ -70,7 +70,8 @@ ext4_file_write(struct kiocb *iocb, const struct iovec *iov,
|
|||
struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
|
||||
size_t length = iov_length(iov, nr_segs);
|
||||
|
||||
if (pos > sbi->s_bitmap_maxbytes)
|
||||
if ((pos > sbi->s_bitmap_maxbytes ||
|
||||
(pos == sbi->s_bitmap_maxbytes && length > 0)))
|
||||
return -EFBIG;
|
||||
|
||||
if (pos + length > sbi->s_bitmap_maxbytes) {
|
||||
|
@ -123,7 +124,7 @@ static int ext4_file_open(struct inode * inode, struct file * filp)
|
|||
if (!IS_ERR(cp)) {
|
||||
memcpy(sbi->s_es->s_last_mounted, cp,
|
||||
sizeof(sbi->s_es->s_last_mounted));
|
||||
sb->s_dirt = 1;
|
||||
ext4_mark_super_dirty(sb);
|
||||
}
|
||||
}
|
||||
return dquot_file_open(inode, filp);
|
||||
|
|
|
@ -279,7 +279,7 @@ out:
|
|||
err = ext4_handle_dirty_metadata(handle, NULL, bitmap_bh);
|
||||
if (!fatal)
|
||||
fatal = err;
|
||||
sb->s_dirt = 1;
|
||||
ext4_mark_super_dirty(sb);
|
||||
} else
|
||||
ext4_error(sb, "bit already cleared for inode %lu", ino);
|
||||
|
||||
|
@ -965,7 +965,7 @@ got:
|
|||
percpu_counter_dec(&sbi->s_freeinodes_counter);
|
||||
if (S_ISDIR(mode))
|
||||
percpu_counter_inc(&sbi->s_dirs_counter);
|
||||
sb->s_dirt = 1;
|
||||
ext4_mark_super_dirty(sb);
|
||||
|
||||
if (sbi->s_log_groups_per_flex) {
|
||||
flex_group = ext4_flex_group(sbi, group);
|
||||
|
|
205
fs/ext4/inode.c
205
fs/ext4/inode.c
|
@ -221,6 +221,7 @@ void ext4_delete_inode(struct inode *inode)
|
|||
"couldn't extend journal (err %d)", err);
|
||||
stop_handle:
|
||||
ext4_journal_stop(handle);
|
||||
ext4_orphan_del(NULL, inode);
|
||||
goto no_delete;
|
||||
}
|
||||
}
|
||||
|
@ -337,9 +338,11 @@ static int ext4_block_to_path(struct inode *inode,
|
|||
return n;
|
||||
}
|
||||
|
||||
static int __ext4_check_blockref(const char *function, struct inode *inode,
|
||||
static int __ext4_check_blockref(const char *function, unsigned int line,
|
||||
struct inode *inode,
|
||||
__le32 *p, unsigned int max)
|
||||
{
|
||||
struct ext4_super_block *es = EXT4_SB(inode->i_sb)->s_es;
|
||||
__le32 *bref = p;
|
||||
unsigned int blk;
|
||||
|
||||
|
@ -348,8 +351,9 @@ static int __ext4_check_blockref(const char *function, struct inode *inode,
|
|||
if (blk &&
|
||||
unlikely(!ext4_data_block_valid(EXT4_SB(inode->i_sb),
|
||||
blk, 1))) {
|
||||
ext4_error_inode(function, inode,
|
||||
"invalid block reference %u", blk);
|
||||
es->s_last_error_block = cpu_to_le64(blk);
|
||||
ext4_error_inode(inode, function, line, blk,
|
||||
"invalid block");
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
@ -358,11 +362,13 @@ static int __ext4_check_blockref(const char *function, struct inode *inode,
|
|||
|
||||
|
||||
#define ext4_check_indirect_blockref(inode, bh) \
|
||||
__ext4_check_blockref(__func__, inode, (__le32 *)(bh)->b_data, \
|
||||
__ext4_check_blockref(__func__, __LINE__, inode, \
|
||||
(__le32 *)(bh)->b_data, \
|
||||
EXT4_ADDR_PER_BLOCK((inode)->i_sb))
|
||||
|
||||
#define ext4_check_inode_blockref(inode) \
|
||||
__ext4_check_blockref(__func__, inode, EXT4_I(inode)->i_data, \
|
||||
__ext4_check_blockref(__func__, __LINE__, inode, \
|
||||
EXT4_I(inode)->i_data, \
|
||||
EXT4_NDIR_BLOCKS)
|
||||
|
||||
/**
|
||||
|
@ -1128,20 +1134,24 @@ void ext4_da_update_reserve_space(struct inode *inode,
|
|||
ext4_discard_preallocations(inode);
|
||||
}
|
||||
|
||||
static int check_block_validity(struct inode *inode, const char *func,
|
||||
static int __check_block_validity(struct inode *inode, const char *func,
|
||||
unsigned int line,
|
||||
struct ext4_map_blocks *map)
|
||||
{
|
||||
if (!ext4_data_block_valid(EXT4_SB(inode->i_sb), map->m_pblk,
|
||||
map->m_len)) {
|
||||
ext4_error_inode(func, inode,
|
||||
"lblock %lu mapped to illegal pblock %llu "
|
||||
"(length %d)", (unsigned long) map->m_lblk,
|
||||
map->m_pblk, map->m_len);
|
||||
ext4_error_inode(inode, func, line, map->m_pblk,
|
||||
"lblock %lu mapped to illegal pblock "
|
||||
"(length %d)", (unsigned long) map->m_lblk,
|
||||
map->m_len);
|
||||
return -EIO;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define check_block_validity(inode, map) \
|
||||
__check_block_validity((inode), __func__, __LINE__, (map))
|
||||
|
||||
/*
|
||||
* Return the number of contiguous dirty pages in a given inode
|
||||
* starting at page frame idx.
|
||||
|
@ -1244,7 +1254,7 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode,
|
|||
up_read((&EXT4_I(inode)->i_data_sem));
|
||||
|
||||
if (retval > 0 && map->m_flags & EXT4_MAP_MAPPED) {
|
||||
int ret = check_block_validity(inode, __func__, map);
|
||||
int ret = check_block_validity(inode, map);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
}
|
||||
|
@ -1324,9 +1334,7 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode,
|
|||
|
||||
up_write((&EXT4_I(inode)->i_data_sem));
|
||||
if (retval > 0 && map->m_flags & EXT4_MAP_MAPPED) {
|
||||
int ret = check_block_validity(inode,
|
||||
"ext4_map_blocks_after_alloc",
|
||||
map);
|
||||
int ret = check_block_validity(inode, map);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
}
|
||||
|
@ -1519,9 +1527,25 @@ static int walk_page_buffers(handle_t *handle,
|
|||
static int do_journal_get_write_access(handle_t *handle,
|
||||
struct buffer_head *bh)
|
||||
{
|
||||
int dirty = buffer_dirty(bh);
|
||||
int ret;
|
||||
|
||||
if (!buffer_mapped(bh) || buffer_freed(bh))
|
||||
return 0;
|
||||
return ext4_journal_get_write_access(handle, bh);
|
||||
/*
|
||||
* __block_prepare_write() could have dirtied some buffers. Clean
|
||||
* the dirty bit as jbd2_journal_get_write_access() could complain
|
||||
* otherwise about fs integrity issues. Setting of the dirty bit
|
||||
* by __block_prepare_write() isn't a real problem here as we clear
|
||||
* the bit before releasing a page lock and thus writeback cannot
|
||||
* ever write the buffer.
|
||||
*/
|
||||
if (dirty)
|
||||
clear_buffer_dirty(bh);
|
||||
ret = ext4_journal_get_write_access(handle, bh);
|
||||
if (!ret && dirty)
|
||||
ret = ext4_handle_dirty_metadata(handle, NULL, bh);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -2194,7 +2218,7 @@ static int mpage_da_map_blocks(struct mpage_da_data *mpd)
|
|||
BUG_ON(!handle);
|
||||
|
||||
/*
|
||||
* Call ext4_get_blocks() to allocate any delayed allocation
|
||||
* Call ext4_map_blocks() to allocate any delayed allocation
|
||||
* blocks, or to convert an uninitialized extent to be
|
||||
* initialized (in the case where we have written into
|
||||
* one or more preallocated blocks).
|
||||
|
@ -2203,7 +2227,7 @@ static int mpage_da_map_blocks(struct mpage_da_data *mpd)
|
|||
* indicate that we are on the delayed allocation path. This
|
||||
* affects functions in many different parts of the allocation
|
||||
* call path. This flag exists primarily because we don't
|
||||
* want to change *many* call functions, so ext4_get_blocks()
|
||||
* want to change *many* call functions, so ext4_map_blocks()
|
||||
* will set the magic i_delalloc_reserved_flag once the
|
||||
* inode's allocation semaphore is taken.
|
||||
*
|
||||
|
@ -2221,6 +2245,8 @@ static int mpage_da_map_blocks(struct mpage_da_data *mpd)
|
|||
|
||||
blks = ext4_map_blocks(handle, mpd->inode, &map, get_blocks_flags);
|
||||
if (blks < 0) {
|
||||
struct super_block *sb = mpd->inode->i_sb;
|
||||
|
||||
err = blks;
|
||||
/*
|
||||
* If get block returns with error we simply
|
||||
|
@ -2231,7 +2257,7 @@ static int mpage_da_map_blocks(struct mpage_da_data *mpd)
|
|||
return 0;
|
||||
|
||||
if (err == -ENOSPC &&
|
||||
ext4_count_free_blocks(mpd->inode->i_sb)) {
|
||||
ext4_count_free_blocks(sb)) {
|
||||
mpd->retval = err;
|
||||
return 0;
|
||||
}
|
||||
|
@ -2243,16 +2269,17 @@ static int mpage_da_map_blocks(struct mpage_da_data *mpd)
|
|||
* writepage and writepages will again try to write
|
||||
* the same.
|
||||
*/
|
||||
ext4_msg(mpd->inode->i_sb, KERN_CRIT,
|
||||
"delayed block allocation failed for inode %lu at "
|
||||
"logical offset %llu with max blocks %zd with "
|
||||
"error %d", mpd->inode->i_ino,
|
||||
(unsigned long long) next,
|
||||
mpd->b_size >> mpd->inode->i_blkbits, err);
|
||||
printk(KERN_CRIT "This should not happen!! "
|
||||
"Data will be lost\n");
|
||||
if (err == -ENOSPC) {
|
||||
ext4_print_free_blocks(mpd->inode);
|
||||
if (!(EXT4_SB(sb)->s_mount_flags & EXT4_MF_FS_ABORTED)) {
|
||||
ext4_msg(sb, KERN_CRIT,
|
||||
"delayed block allocation failed for inode %lu "
|
||||
"at logical offset %llu with max blocks %zd "
|
||||
"with error %d", mpd->inode->i_ino,
|
||||
(unsigned long long) next,
|
||||
mpd->b_size >> mpd->inode->i_blkbits, err);
|
||||
ext4_msg(sb, KERN_CRIT,
|
||||
"This should not happen!! Data will be lost\n");
|
||||
if (err == -ENOSPC)
|
||||
ext4_print_free_blocks(mpd->inode);
|
||||
}
|
||||
/* invalidate all the pages */
|
||||
ext4_da_block_invalidatepages(mpd, next,
|
||||
|
@ -2320,7 +2347,7 @@ static void mpage_add_bh_to_extent(struct mpage_da_data *mpd,
|
|||
* XXX Don't go larger than mballoc is willing to allocate
|
||||
* This is a stopgap solution. We eventually need to fold
|
||||
* mpage_da_submit_io() into this function and then call
|
||||
* ext4_get_blocks() multiple times in a loop
|
||||
* ext4_map_blocks() multiple times in a loop
|
||||
*/
|
||||
if (nrblocks >= 8*1024*1024/mpd->inode->i_sb->s_blocksize)
|
||||
goto flush_it;
|
||||
|
@ -2553,18 +2580,16 @@ static int ext4_da_get_block_prep(struct inode *inode, sector_t iblock,
|
|||
/*
|
||||
* This function is used as a standard get_block_t calback function
|
||||
* when there is no desire to allocate any blocks. It is used as a
|
||||
* callback function for block_prepare_write(), nobh_writepage(), and
|
||||
* block_write_full_page(). These functions should only try to map a
|
||||
* single block at a time.
|
||||
* callback function for block_prepare_write() and block_write_full_page().
|
||||
* These functions should only try to map a single block at a time.
|
||||
*
|
||||
* Since this function doesn't do block allocations even if the caller
|
||||
* requests it by passing in create=1, it is critically important that
|
||||
* any caller checks to make sure that any buffer heads are returned
|
||||
* by this function are either all already mapped or marked for
|
||||
* delayed allocation before calling nobh_writepage() or
|
||||
* block_write_full_page(). Otherwise, b_blocknr could be left
|
||||
* unitialized, and the page write functions will be taken by
|
||||
* surprise.
|
||||
* delayed allocation before calling block_write_full_page(). Otherwise,
|
||||
* b_blocknr could be left unitialized, and the page write functions will
|
||||
* be taken by surprise.
|
||||
*/
|
||||
static int noalloc_get_block_write(struct inode *inode, sector_t iblock,
|
||||
struct buffer_head *bh_result, int create)
|
||||
|
@ -2749,9 +2774,7 @@ static int ext4_writepage(struct page *page,
|
|||
return __ext4_journalled_writepage(page, len);
|
||||
}
|
||||
|
||||
if (test_opt(inode->i_sb, NOBH) && ext4_should_writeback_data(inode))
|
||||
ret = nobh_writepage(page, noalloc_get_block_write, wbc);
|
||||
else if (page_bufs && buffer_uninit(page_bufs)) {
|
||||
if (page_bufs && buffer_uninit(page_bufs)) {
|
||||
ext4_set_bh_endio(page_bufs, inode);
|
||||
ret = block_write_full_page_endio(page, noalloc_get_block_write,
|
||||
wbc, ext4_end_io_buffer_write);
|
||||
|
@ -3146,13 +3169,10 @@ static int ext4_da_write_begin(struct file *file, struct address_space *mapping,
|
|||
int ret, retries = 0;
|
||||
struct page *page;
|
||||
pgoff_t index;
|
||||
unsigned from, to;
|
||||
struct inode *inode = mapping->host;
|
||||
handle_t *handle;
|
||||
|
||||
index = pos >> PAGE_CACHE_SHIFT;
|
||||
from = pos & (PAGE_CACHE_SIZE - 1);
|
||||
to = from + len;
|
||||
|
||||
if (ext4_nonda_switch(inode->i_sb)) {
|
||||
*fsdata = (void *)FALL_BACK_TO_NONDELALLOC;
|
||||
|
@ -3668,6 +3688,8 @@ static int ext4_end_io_nolock(ext4_io_end_t *io)
|
|||
return ret;
|
||||
}
|
||||
|
||||
if (io->iocb)
|
||||
aio_complete(io->iocb, io->result, 0);
|
||||
/* clear the DIO AIO unwritten flag */
|
||||
io->flag = 0;
|
||||
return ret;
|
||||
|
@ -3767,6 +3789,8 @@ static ext4_io_end_t *ext4_init_io_end (struct inode *inode, gfp_t flags)
|
|||
io->offset = 0;
|
||||
io->size = 0;
|
||||
io->page = NULL;
|
||||
io->iocb = NULL;
|
||||
io->result = 0;
|
||||
INIT_WORK(&io->work, ext4_end_io_work);
|
||||
INIT_LIST_HEAD(&io->list);
|
||||
}
|
||||
|
@ -3796,12 +3820,18 @@ static void ext4_end_io_dio(struct kiocb *iocb, loff_t offset,
|
|||
if (io_end->flag != EXT4_IO_UNWRITTEN){
|
||||
ext4_free_io_end(io_end);
|
||||
iocb->private = NULL;
|
||||
goto out;
|
||||
out:
|
||||
if (is_async)
|
||||
aio_complete(iocb, ret, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
io_end->offset = offset;
|
||||
io_end->size = size;
|
||||
io_end->flag = EXT4_IO_UNWRITTEN;
|
||||
if (is_async) {
|
||||
io_end->iocb = iocb;
|
||||
io_end->result = ret;
|
||||
}
|
||||
wq = EXT4_SB(io_end->inode->i_sb)->dio_unwritten_wq;
|
||||
|
||||
/* queue the work to convert unwritten extents to written */
|
||||
|
@ -3813,9 +3843,6 @@ static void ext4_end_io_dio(struct kiocb *iocb, loff_t offset,
|
|||
list_add_tail(&io_end->list, &ei->i_completed_io_list);
|
||||
spin_unlock_irqrestore(&ei->i_completed_io_lock, flags);
|
||||
iocb->private = NULL;
|
||||
out:
|
||||
if (is_async)
|
||||
aio_complete(iocb, ret, 0);
|
||||
}
|
||||
|
||||
static void ext4_end_io_buffer_write(struct buffer_head *bh, int uptodate)
|
||||
|
@ -3941,7 +3968,7 @@ static ssize_t ext4_ext_direct_IO(int rw, struct kiocb *iocb,
|
|||
return -ENOMEM;
|
||||
/*
|
||||
* we save the io structure for current async
|
||||
* direct IO, so that later ext4_get_blocks()
|
||||
* direct IO, so that later ext4_map_blocks()
|
||||
* could flag the io structure whether there
|
||||
* is a unwritten extents needs to be converted
|
||||
* when IO is completed.
|
||||
|
@ -4132,17 +4159,6 @@ int ext4_block_truncate_page(handle_t *handle,
|
|||
length = blocksize - (offset & (blocksize - 1));
|
||||
iblock = index << (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits);
|
||||
|
||||
/*
|
||||
* For "nobh" option, we can only work if we don't need to
|
||||
* read-in the page - otherwise we create buffers to do the IO.
|
||||
*/
|
||||
if (!page_has_buffers(page) && test_opt(inode->i_sb, NOBH) &&
|
||||
ext4_should_writeback_data(inode) && PageUptodate(page)) {
|
||||
zero_user(page, offset, length);
|
||||
set_page_dirty(page);
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (!page_has_buffers(page))
|
||||
create_empty_buffers(page, blocksize, 0);
|
||||
|
||||
|
@ -4492,9 +4508,8 @@ static void ext4_free_branches(handle_t *handle, struct inode *inode,
|
|||
* (should be rare).
|
||||
*/
|
||||
if (!bh) {
|
||||
EXT4_ERROR_INODE(inode,
|
||||
"Read failure block=%llu",
|
||||
(unsigned long long) nr);
|
||||
EXT4_ERROR_INODE_BLOCK(inode, nr,
|
||||
"Read failure");
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -4505,27 +4520,6 @@ static void ext4_free_branches(handle_t *handle, struct inode *inode,
|
|||
(__le32 *) bh->b_data + addr_per_block,
|
||||
depth);
|
||||
|
||||
/*
|
||||
* We've probably journalled the indirect block several
|
||||
* times during the truncate. But it's no longer
|
||||
* needed and we now drop it from the transaction via
|
||||
* jbd2_journal_revoke().
|
||||
*
|
||||
* That's easy if it's exclusively part of this
|
||||
* transaction. But if it's part of the committing
|
||||
* transaction then jbd2_journal_forget() will simply
|
||||
* brelse() it. That means that if the underlying
|
||||
* block is reallocated in ext4_get_block(),
|
||||
* unmap_underlying_metadata() will find this block
|
||||
* and will try to get rid of it. damn, damn.
|
||||
*
|
||||
* If this block has already been committed to the
|
||||
* journal, a revoke record will be written. And
|
||||
* revoke records must be emitted *before* clearing
|
||||
* this block's bit in the bitmaps.
|
||||
*/
|
||||
ext4_forget(handle, 1, inode, bh, bh->b_blocknr);
|
||||
|
||||
/*
|
||||
* Everything below this this pointer has been
|
||||
* released. Now let this top-of-subtree go.
|
||||
|
@ -4550,8 +4544,20 @@ static void ext4_free_branches(handle_t *handle, struct inode *inode,
|
|||
blocks_for_truncate(inode));
|
||||
}
|
||||
|
||||
/*
|
||||
* The forget flag here is critical because if
|
||||
* we are journaling (and not doing data
|
||||
* journaling), we have to make sure a revoke
|
||||
* record is written to prevent the journal
|
||||
* replay from overwriting the (former)
|
||||
* indirect block if it gets reallocated as a
|
||||
* data block. This must happen in the same
|
||||
* transaction where the data blocks are
|
||||
* actually freed.
|
||||
*/
|
||||
ext4_free_blocks(handle, inode, 0, nr, 1,
|
||||
EXT4_FREE_BLOCKS_METADATA);
|
||||
EXT4_FREE_BLOCKS_METADATA|
|
||||
EXT4_FREE_BLOCKS_FORGET);
|
||||
|
||||
if (parent_bh) {
|
||||
/*
|
||||
|
@ -4809,8 +4815,8 @@ static int __ext4_get_inode_loc(struct inode *inode,
|
|||
|
||||
bh = sb_getblk(sb, block);
|
||||
if (!bh) {
|
||||
EXT4_ERROR_INODE(inode, "unable to read inode block - "
|
||||
"block %llu", block);
|
||||
EXT4_ERROR_INODE_BLOCK(inode, block,
|
||||
"unable to read itable block");
|
||||
return -EIO;
|
||||
}
|
||||
if (!buffer_uptodate(bh)) {
|
||||
|
@ -4908,8 +4914,8 @@ make_io:
|
|||
submit_bh(READ_META, bh);
|
||||
wait_on_buffer(bh);
|
||||
if (!buffer_uptodate(bh)) {
|
||||
EXT4_ERROR_INODE(inode, "unable to read inode "
|
||||
"block %llu", block);
|
||||
EXT4_ERROR_INODE_BLOCK(inode, block,
|
||||
"unable to read itable block");
|
||||
brelse(bh);
|
||||
return -EIO;
|
||||
}
|
||||
|
@ -4980,7 +4986,7 @@ static blkcnt_t ext4_inode_blocks(struct ext4_inode *raw_inode,
|
|||
/* we are using combined 48 bit field */
|
||||
i_blocks = ((u64)le16_to_cpu(raw_inode->i_blocks_high)) << 32 |
|
||||
le32_to_cpu(raw_inode->i_blocks_lo);
|
||||
if (ei->i_flags & EXT4_HUGE_FILE_FL) {
|
||||
if (ext4_test_inode_flag(inode, EXT4_INODE_HUGE_FILE)) {
|
||||
/* i_blocks represent file system block size */
|
||||
return i_blocks << (inode->i_blkbits - 9);
|
||||
} else {
|
||||
|
@ -5076,7 +5082,7 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
|
|||
transaction_t *transaction;
|
||||
tid_t tid;
|
||||
|
||||
spin_lock(&journal->j_state_lock);
|
||||
read_lock(&journal->j_state_lock);
|
||||
if (journal->j_running_transaction)
|
||||
transaction = journal->j_running_transaction;
|
||||
else
|
||||
|
@ -5085,7 +5091,7 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
|
|||
tid = transaction->t_tid;
|
||||
else
|
||||
tid = journal->j_commit_sequence;
|
||||
spin_unlock(&journal->j_state_lock);
|
||||
read_unlock(&journal->j_state_lock);
|
||||
ei->i_sync_tid = tid;
|
||||
ei->i_datasync_tid = tid;
|
||||
}
|
||||
|
@ -5130,7 +5136,7 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
|
|||
ei->i_file_acl);
|
||||
ret = -EIO;
|
||||
goto bad_inode;
|
||||
} else if (ei->i_flags & EXT4_EXTENTS_FL) {
|
||||
} else if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) {
|
||||
if (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
|
||||
(S_ISLNK(inode->i_mode) &&
|
||||
!ext4_inode_is_fast_symlink(inode)))
|
||||
|
@ -5410,9 +5416,8 @@ int ext4_write_inode(struct inode *inode, struct writeback_control *wbc)
|
|||
if (wbc->sync_mode == WB_SYNC_ALL)
|
||||
sync_dirty_buffer(iloc.bh);
|
||||
if (buffer_req(iloc.bh) && !buffer_uptodate(iloc.bh)) {
|
||||
EXT4_ERROR_INODE(inode,
|
||||
"IO error syncing inode (block=%llu)",
|
||||
(unsigned long long) iloc.bh->b_blocknr);
|
||||
EXT4_ERROR_INODE_BLOCK(inode, iloc.bh->b_blocknr,
|
||||
"IO error syncing inode");
|
||||
err = -EIO;
|
||||
}
|
||||
brelse(iloc.bh);
|
||||
|
@ -5487,10 +5492,8 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr)
|
|||
if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) {
|
||||
struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
|
||||
|
||||
if (attr->ia_size > sbi->s_bitmap_maxbytes) {
|
||||
error = -EFBIG;
|
||||
goto err_out;
|
||||
}
|
||||
if (attr->ia_size > sbi->s_bitmap_maxbytes)
|
||||
return -EFBIG;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5692,7 +5695,7 @@ int ext4_writepage_trans_blocks(struct inode *inode)
|
|||
* Calculate the journal credits for a chunk of data modification.
|
||||
*
|
||||
* This is called from DIO, fallocate or whoever calling
|
||||
* ext4_get_blocks() to map/allocate a chunk of contiguous disk blocks.
|
||||
* ext4_map_blocks() to map/allocate a chunk of contiguous disk blocks.
|
||||
*
|
||||
* journal buffers for data blocks are not included here, as DIO
|
||||
* and fallocate do no need to journal data buffers.
|
||||
|
@ -5758,7 +5761,6 @@ static int ext4_expand_extra_isize(struct inode *inode,
|
|||
{
|
||||
struct ext4_inode *raw_inode;
|
||||
struct ext4_xattr_ibody_header *header;
|
||||
struct ext4_xattr_entry *entry;
|
||||
|
||||
if (EXT4_I(inode)->i_extra_isize >= new_extra_isize)
|
||||
return 0;
|
||||
|
@ -5766,7 +5768,6 @@ static int ext4_expand_extra_isize(struct inode *inode,
|
|||
raw_inode = ext4_raw_inode(&iloc);
|
||||
|
||||
header = IHDR(inode, raw_inode);
|
||||
entry = IFIRST(header);
|
||||
|
||||
/* No extended attributes present */
|
||||
if (!ext4_test_inode_state(inode, EXT4_STATE_XATTR) ||
|
||||
|
|
|
@ -446,10 +446,11 @@ static void mb_free_blocks_double(struct inode *inode, struct ext4_buddy *e4b,
|
|||
blocknr = ext4_group_first_block_no(sb, e4b->bd_group);
|
||||
blocknr += first + i;
|
||||
ext4_grp_locked_error(sb, e4b->bd_group,
|
||||
__func__, "double-free of inode"
|
||||
" %lu's block %llu(bit %u in group %u)",
|
||||
inode ? inode->i_ino : 0, blocknr,
|
||||
first + i, e4b->bd_group);
|
||||
inode ? inode->i_ino : 0,
|
||||
blocknr,
|
||||
"freeing block already freed "
|
||||
"(bit %u)",
|
||||
first + i);
|
||||
}
|
||||
mb_clear_bit(first + i, e4b->bd_info->bb_bitmap);
|
||||
}
|
||||
|
@ -712,9 +713,9 @@ void ext4_mb_generate_buddy(struct super_block *sb,
|
|||
grp->bb_fragments = fragments;
|
||||
|
||||
if (free != grp->bb_free) {
|
||||
ext4_grp_locked_error(sb, group, __func__,
|
||||
"EXT4-fs: group %u: %u blocks in bitmap, %u in gd",
|
||||
group, free, grp->bb_free);
|
||||
ext4_grp_locked_error(sb, group, 0, 0,
|
||||
"%u blocks in bitmap, %u in gd",
|
||||
free, grp->bb_free);
|
||||
/*
|
||||
* If we intent to continue, we consider group descritor
|
||||
* corrupt and update bb_free using bitmap value
|
||||
|
@ -1296,10 +1297,10 @@ static void mb_free_blocks(struct inode *inode, struct ext4_buddy *e4b,
|
|||
blocknr = ext4_group_first_block_no(sb, e4b->bd_group);
|
||||
blocknr += block;
|
||||
ext4_grp_locked_error(sb, e4b->bd_group,
|
||||
__func__, "double-free of inode"
|
||||
" %lu's block %llu(bit %u in group %u)",
|
||||
inode ? inode->i_ino : 0, blocknr, block,
|
||||
e4b->bd_group);
|
||||
inode ? inode->i_ino : 0,
|
||||
blocknr,
|
||||
"freeing already freed block "
|
||||
"(bit %u)", block);
|
||||
}
|
||||
mb_clear_bit(block, EXT4_MB_BITMAP(e4b));
|
||||
e4b->bd_info->bb_counters[order]++;
|
||||
|
@ -1788,8 +1789,8 @@ void ext4_mb_complex_scan_group(struct ext4_allocation_context *ac,
|
|||
* free blocks even though group info says we
|
||||
* we have free blocks
|
||||
*/
|
||||
ext4_grp_locked_error(sb, e4b->bd_group,
|
||||
__func__, "%d free blocks as per "
|
||||
ext4_grp_locked_error(sb, e4b->bd_group, 0, 0,
|
||||
"%d free blocks as per "
|
||||
"group info. But bitmap says 0",
|
||||
free);
|
||||
break;
|
||||
|
@ -1798,8 +1799,8 @@ 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_grp_locked_error(sb, e4b->bd_group,
|
||||
__func__, "%d free blocks as per "
|
||||
ext4_grp_locked_error(sb, e4b->bd_group, 0, 0,
|
||||
"%d free blocks as per "
|
||||
"group info. But got %d blocks",
|
||||
free, ex.fe_len);
|
||||
/*
|
||||
|
@ -1821,8 +1822,7 @@ void ext4_mb_complex_scan_group(struct ext4_allocation_context *ac,
|
|||
|
||||
/*
|
||||
* This is a special case for storages like raid5
|
||||
* we try to find stripe-aligned chunks for stripe-size requests
|
||||
* XXX should do so at least for multiples of stripe size as well
|
||||
* we try to find stripe-aligned chunks for stripe-size-multiple requests
|
||||
*/
|
||||
static noinline_for_stack
|
||||
void ext4_mb_scan_aligned(struct ext4_allocation_context *ac,
|
||||
|
@ -1999,7 +1999,6 @@ ext4_mb_regular_allocator(struct ext4_allocation_context *ac)
|
|||
ext4_group_t ngroups, group, i;
|
||||
int cr;
|
||||
int err = 0;
|
||||
int bsbits;
|
||||
struct ext4_sb_info *sbi;
|
||||
struct super_block *sb;
|
||||
struct ext4_buddy e4b;
|
||||
|
@ -2041,8 +2040,6 @@ ext4_mb_regular_allocator(struct ext4_allocation_context *ac)
|
|||
ac->ac_2order = i - 1;
|
||||
}
|
||||
|
||||
bsbits = ac->ac_sb->s_blocksize_bits;
|
||||
|
||||
/* if stream allocation is enabled, use global goal */
|
||||
if (ac->ac_flags & EXT4_MB_STREAM_ALLOC) {
|
||||
/* TBD: may be hot point */
|
||||
|
@ -2094,8 +2091,8 @@ repeat:
|
|||
ac->ac_groups_scanned++;
|
||||
if (cr == 0)
|
||||
ext4_mb_simple_scan_group(ac, &e4b);
|
||||
else if (cr == 1 &&
|
||||
ac->ac_g_ex.fe_len == sbi->s_stripe)
|
||||
else if (cr == 1 && sbi->s_stripe &&
|
||||
!(ac->ac_g_ex.fe_len % sbi->s_stripe))
|
||||
ext4_mb_scan_aligned(ac, &e4b);
|
||||
else
|
||||
ext4_mb_complex_scan_group(ac, &e4b);
|
||||
|
@ -2221,7 +2218,7 @@ static int ext4_mb_seq_groups_open(struct inode *inode, struct file *file)
|
|||
|
||||
rc = seq_open(file, &ext4_mb_seq_groups_ops);
|
||||
if (rc == 0) {
|
||||
struct seq_file *m = (struct seq_file *)file->private_data;
|
||||
struct seq_file *m = file->private_data;
|
||||
m->private = sb;
|
||||
}
|
||||
return rc;
|
||||
|
@ -2560,6 +2557,22 @@ int ext4_mb_release(struct super_block *sb)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline void ext4_issue_discard(struct super_block *sb,
|
||||
ext4_group_t block_group, ext4_grpblk_t block, int count)
|
||||
{
|
||||
int ret;
|
||||
ext4_fsblk_t discard_block;
|
||||
|
||||
discard_block = block + ext4_group_first_block_no(sb, block_group);
|
||||
trace_ext4_discard_blocks(sb,
|
||||
(unsigned long long) discard_block, count);
|
||||
ret = sb_issue_discard(sb, discard_block, count);
|
||||
if (ret == EOPNOTSUPP) {
|
||||
ext4_warning(sb, "discard not supported, disabling");
|
||||
clear_opt(EXT4_SB(sb)->s_mount_opt, DISCARD);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is called by the jbd2 layer once the commit has finished,
|
||||
* so we know we can free the blocks that were released with that commit.
|
||||
|
@ -2579,22 +2592,9 @@ static void release_blocks_on_commit(journal_t *journal, transaction_t *txn)
|
|||
mb_debug(1, "gonna free %u blocks in group %u (0x%p):",
|
||||
entry->count, entry->group, entry);
|
||||
|
||||
if (test_opt(sb, DISCARD)) {
|
||||
int ret;
|
||||
ext4_fsblk_t discard_block;
|
||||
|
||||
discard_block = entry->start_blk +
|
||||
ext4_group_first_block_no(sb, entry->group);
|
||||
trace_ext4_discard_blocks(sb,
|
||||
(unsigned long long)discard_block,
|
||||
entry->count);
|
||||
ret = sb_issue_discard(sb, discard_block, entry->count);
|
||||
if (ret == EOPNOTSUPP) {
|
||||
ext4_warning(sb,
|
||||
"discard not supported, disabling");
|
||||
clear_opt(EXT4_SB(sb)->s_mount_opt, DISCARD);
|
||||
}
|
||||
}
|
||||
if (test_opt(sb, DISCARD))
|
||||
ext4_issue_discard(sb, entry->group,
|
||||
entry->start_blk, entry->count);
|
||||
|
||||
err = ext4_mb_load_buddy(sb, entry->group, &e4b);
|
||||
/* we expect to find existing buddy because it's pinned */
|
||||
|
@ -2712,7 +2712,6 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac,
|
|||
handle_t *handle, unsigned int reserv_blks)
|
||||
{
|
||||
struct buffer_head *bitmap_bh = NULL;
|
||||
struct ext4_super_block *es;
|
||||
struct ext4_group_desc *gdp;
|
||||
struct buffer_head *gdp_bh;
|
||||
struct ext4_sb_info *sbi;
|
||||
|
@ -2725,8 +2724,6 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac,
|
|||
|
||||
sb = ac->ac_sb;
|
||||
sbi = EXT4_SB(sb);
|
||||
es = sbi->s_es;
|
||||
|
||||
|
||||
err = -EIO;
|
||||
bitmap_bh = ext4_read_block_bitmap(sb, ac->ac_b_ex.fe_group);
|
||||
|
@ -2812,7 +2809,7 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac,
|
|||
err = ext4_handle_dirty_metadata(handle, NULL, gdp_bh);
|
||||
|
||||
out_err:
|
||||
sb->s_dirt = 1;
|
||||
ext4_mark_super_dirty(sb);
|
||||
brelse(bitmap_bh);
|
||||
return err;
|
||||
}
|
||||
|
@ -2850,7 +2847,7 @@ ext4_mb_normalize_request(struct ext4_allocation_context *ac,
|
|||
int bsbits, max;
|
||||
ext4_lblk_t end;
|
||||
loff_t size, orig_size, start_off;
|
||||
ext4_lblk_t start, orig_start;
|
||||
ext4_lblk_t start;
|
||||
struct ext4_inode_info *ei = EXT4_I(ac->ac_inode);
|
||||
struct ext4_prealloc_space *pa;
|
||||
|
||||
|
@ -2881,6 +2878,7 @@ ext4_mb_normalize_request(struct ext4_allocation_context *ac,
|
|||
size = size << bsbits;
|
||||
if (size < i_size_read(ac->ac_inode))
|
||||
size = i_size_read(ac->ac_inode);
|
||||
orig_size = size;
|
||||
|
||||
/* max size of free chunks */
|
||||
max = 2 << bsbits;
|
||||
|
@ -2922,8 +2920,8 @@ ext4_mb_normalize_request(struct ext4_allocation_context *ac,
|
|||
start_off = (loff_t)ac->ac_o_ex.fe_logical << bsbits;
|
||||
size = ac->ac_o_ex.fe_len << bsbits;
|
||||
}
|
||||
orig_size = size = size >> bsbits;
|
||||
orig_start = start = start_off >> bsbits;
|
||||
size = size >> bsbits;
|
||||
start = start_off >> bsbits;
|
||||
|
||||
/* don't cover already allocated blocks in selected range */
|
||||
if (ar->pleft && start <= ar->lleft) {
|
||||
|
@ -3547,7 +3545,6 @@ ext4_mb_release_inode_pa(struct ext4_buddy *e4b, struct buffer_head *bitmap_bh,
|
|||
ext4_group_t group;
|
||||
ext4_grpblk_t bit;
|
||||
unsigned long long grp_blk_start;
|
||||
sector_t start;
|
||||
int err = 0;
|
||||
int free = 0;
|
||||
|
||||
|
@ -3567,10 +3564,9 @@ ext4_mb_release_inode_pa(struct ext4_buddy *e4b, struct buffer_head *bitmap_bh,
|
|||
if (bit >= end)
|
||||
break;
|
||||
next = mb_find_next_bit(bitmap_bh->b_data, end, bit);
|
||||
start = ext4_group_first_block_no(sb, group) + bit;
|
||||
mb_debug(1, " free preallocated %u/%u in group %u\n",
|
||||
(unsigned) start, (unsigned) next - bit,
|
||||
(unsigned) group);
|
||||
(unsigned) ext4_group_first_block_no(sb, group) + bit,
|
||||
(unsigned) next - bit, (unsigned) group);
|
||||
free += next - bit;
|
||||
|
||||
if (ac) {
|
||||
|
@ -3581,7 +3577,7 @@ ext4_mb_release_inode_pa(struct ext4_buddy *e4b, struct buffer_head *bitmap_bh,
|
|||
trace_ext4_mballoc_discard(ac);
|
||||
}
|
||||
|
||||
trace_ext4_mb_release_inode_pa(ac, pa, grp_blk_start + bit,
|
||||
trace_ext4_mb_release_inode_pa(sb, ac, pa, grp_blk_start + bit,
|
||||
next - bit);
|
||||
mb_free_blocks(pa->pa_inode, e4b, bit, next - bit);
|
||||
bit = next + 1;
|
||||
|
@ -3591,8 +3587,7 @@ ext4_mb_release_inode_pa(struct ext4_buddy *e4b, struct buffer_head *bitmap_bh,
|
|||
pa, (unsigned long) pa->pa_lstart,
|
||||
(unsigned long) pa->pa_pstart,
|
||||
(unsigned long) pa->pa_len);
|
||||
ext4_grp_locked_error(sb, group,
|
||||
__func__, "free %u, pa_free %u",
|
||||
ext4_grp_locked_error(sb, group, 0, 0, "free %u, pa_free %u",
|
||||
free, pa->pa_free);
|
||||
/*
|
||||
* pa is already deleted so we use the value obtained
|
||||
|
@ -3613,7 +3608,7 @@ ext4_mb_release_group_pa(struct ext4_buddy *e4b,
|
|||
ext4_group_t group;
|
||||
ext4_grpblk_t bit;
|
||||
|
||||
trace_ext4_mb_release_group_pa(ac, pa);
|
||||
trace_ext4_mb_release_group_pa(sb, ac, pa);
|
||||
BUG_ON(pa->pa_deleted == 0);
|
||||
ext4_get_group_no_and_offset(sb, pa->pa_pstart, &group, &bit);
|
||||
BUG_ON(group != e4b->bd_group && pa->pa_len != 0);
|
||||
|
@ -3889,6 +3884,9 @@ static void ext4_mb_show_ac(struct ext4_allocation_context *ac)
|
|||
struct super_block *sb = ac->ac_sb;
|
||||
ext4_group_t ngroups, i;
|
||||
|
||||
if (EXT4_SB(sb)->s_mount_flags & EXT4_MF_FS_ABORTED)
|
||||
return;
|
||||
|
||||
printk(KERN_ERR "EXT4-fs: Can't allocate:"
|
||||
" Allocation context details:\n");
|
||||
printk(KERN_ERR "EXT4-fs: status %d flags %d\n",
|
||||
|
@ -4255,7 +4253,7 @@ static int ext4_mb_discard_preallocations(struct super_block *sb, int needed)
|
|||
* to usual allocation
|
||||
*/
|
||||
ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle,
|
||||
struct ext4_allocation_request *ar, int *errp)
|
||||
struct ext4_allocation_request *ar, int *errp)
|
||||
{
|
||||
int freed;
|
||||
struct ext4_allocation_context *ac = NULL;
|
||||
|
@ -4299,7 +4297,7 @@ ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle,
|
|||
inquota = ar->len;
|
||||
if (ar->len == 0) {
|
||||
*errp = -EDQUOT;
|
||||
goto out3;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4307,13 +4305,13 @@ ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle,
|
|||
if (!ac) {
|
||||
ar->len = 0;
|
||||
*errp = -ENOMEM;
|
||||
goto out1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
*errp = ext4_mb_initialize_context(ac, ar);
|
||||
if (*errp) {
|
||||
ar->len = 0;
|
||||
goto out2;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ac->ac_op = EXT4_MB_HISTORY_PREALLOC;
|
||||
|
@ -4322,7 +4320,9 @@ ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle,
|
|||
ext4_mb_normalize_request(ac, ar);
|
||||
repeat:
|
||||
/* allocate space in core */
|
||||
ext4_mb_regular_allocator(ac);
|
||||
*errp = ext4_mb_regular_allocator(ac);
|
||||
if (*errp)
|
||||
goto errout;
|
||||
|
||||
/* as we've just preallocated more space than
|
||||
* user requested orinally, we store allocated
|
||||
|
@ -4333,7 +4333,7 @@ repeat:
|
|||
}
|
||||
if (likely(ac->ac_status == AC_STATUS_FOUND)) {
|
||||
*errp = ext4_mb_mark_diskspace_used(ac, handle, reserv_blks);
|
||||
if (*errp == -EAGAIN) {
|
||||
if (*errp == -EAGAIN) {
|
||||
/*
|
||||
* drop the reference that we took
|
||||
* in ext4_mb_use_best_found
|
||||
|
@ -4344,12 +4344,10 @@ repeat:
|
|||
ac->ac_b_ex.fe_len = 0;
|
||||
ac->ac_status = AC_STATUS_CONTINUE;
|
||||
goto repeat;
|
||||
} else if (*errp) {
|
||||
} else if (*errp)
|
||||
errout:
|
||||
ext4_discard_allocated_blocks(ac);
|
||||
ac->ac_b_ex.fe_len = 0;
|
||||
ar->len = 0;
|
||||
ext4_mb_show_ac(ac);
|
||||
} else {
|
||||
else {
|
||||
block = ext4_grp_offs_to_block(sb, &ac->ac_b_ex);
|
||||
ar->len = ac->ac_b_ex.fe_len;
|
||||
}
|
||||
|
@ -4358,19 +4356,19 @@ repeat:
|
|||
if (freed)
|
||||
goto repeat;
|
||||
*errp = -ENOSPC;
|
||||
}
|
||||
|
||||
if (*errp) {
|
||||
ac->ac_b_ex.fe_len = 0;
|
||||
ar->len = 0;
|
||||
ext4_mb_show_ac(ac);
|
||||
}
|
||||
|
||||
ext4_mb_release_context(ac);
|
||||
|
||||
out2:
|
||||
kmem_cache_free(ext4_ac_cachep, ac);
|
||||
out1:
|
||||
out:
|
||||
if (ac)
|
||||
kmem_cache_free(ext4_ac_cachep, ac);
|
||||
if (inquota && ar->len < inquota)
|
||||
dquot_free_block(ar->inode, inquota - ar->len);
|
||||
out3:
|
||||
if (!ar->len) {
|
||||
if (!EXT4_I(ar->inode)->i_delalloc_reserved_flag)
|
||||
/* release all the reserved blocks if non delalloc */
|
||||
|
@ -4402,6 +4400,7 @@ static noinline_for_stack int
|
|||
ext4_mb_free_metadata(handle_t *handle, struct ext4_buddy *e4b,
|
||||
struct ext4_free_data *new_entry)
|
||||
{
|
||||
ext4_group_t group = e4b->bd_group;
|
||||
ext4_grpblk_t block;
|
||||
struct ext4_free_data *entry;
|
||||
struct ext4_group_info *db = e4b->bd_info;
|
||||
|
@ -4434,9 +4433,9 @@ ext4_mb_free_metadata(handle_t *handle, struct ext4_buddy *e4b,
|
|||
else if (block >= (entry->start_blk + entry->count))
|
||||
n = &(*n)->rb_right;
|
||||
else {
|
||||
ext4_grp_locked_error(sb, e4b->bd_group, __func__,
|
||||
"Double free of blocks %d (%d %d)",
|
||||
block, entry->start_blk, entry->count);
|
||||
ext4_grp_locked_error(sb, group, 0,
|
||||
ext4_group_first_block_no(sb, group) + block,
|
||||
"Block already on to-be-freed list");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -4494,7 +4493,6 @@ void ext4_free_blocks(handle_t *handle, struct inode *inode,
|
|||
struct super_block *sb = inode->i_sb;
|
||||
struct ext4_allocation_context *ac = NULL;
|
||||
struct ext4_group_desc *gdp;
|
||||
struct ext4_super_block *es;
|
||||
unsigned long freed = 0;
|
||||
unsigned int overflow;
|
||||
ext4_grpblk_t bit;
|
||||
|
@ -4513,7 +4511,6 @@ void ext4_free_blocks(handle_t *handle, struct inode *inode,
|
|||
}
|
||||
|
||||
sbi = EXT4_SB(sb);
|
||||
es = EXT4_SB(sb)->s_es;
|
||||
if (!(flags & EXT4_FREE_BLOCKS_VALIDATED) &&
|
||||
!ext4_data_block_valid(sbi, block, count)) {
|
||||
ext4_error(sb, "Freeing blocks not in datazone - "
|
||||
|
@ -4647,6 +4644,8 @@ do_more:
|
|||
mb_clear_bits(bitmap_bh->b_data, bit, count);
|
||||
mb_free_blocks(inode, &e4b, bit, count);
|
||||
ext4_mb_return_to_preallocation(inode, &e4b, block, count);
|
||||
if (test_opt(sb, DISCARD))
|
||||
ext4_issue_discard(sb, block_group, bit, count);
|
||||
}
|
||||
|
||||
ret = ext4_free_blks_count(sb, gdp) + count;
|
||||
|
@ -4680,7 +4679,7 @@ do_more:
|
|||
put_bh(bitmap_bh);
|
||||
goto do_more;
|
||||
}
|
||||
sb->s_dirt = 1;
|
||||
ext4_mark_super_dirty(sb);
|
||||
error_return:
|
||||
if (freed)
|
||||
dquot_free_block(inode, freed);
|
||||
|
|
|
@ -376,7 +376,7 @@ static int ext4_ext_swap_inode_data(handle_t *handle, struct inode *inode,
|
|||
* We have the extent map build with the tmp inode.
|
||||
* Now copy the i_data across
|
||||
*/
|
||||
ei->i_flags |= EXT4_EXTENTS_FL;
|
||||
ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS);
|
||||
memcpy(ei->i_data, tmp_ei->i_data, sizeof(ei->i_data));
|
||||
|
||||
/*
|
||||
|
|
|
@ -148,17 +148,17 @@ mext_next_extent(struct inode *inode, struct ext4_ext_path *path,
|
|||
*/
|
||||
static int
|
||||
mext_check_null_inode(struct inode *inode1, struct inode *inode2,
|
||||
const char *function)
|
||||
const char *function, unsigned int line)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (inode1 == NULL) {
|
||||
__ext4_error(inode2->i_sb, function,
|
||||
__ext4_error(inode2->i_sb, function, line,
|
||||
"Both inodes should not be NULL: "
|
||||
"inode1 NULL inode2 %lu", inode2->i_ino);
|
||||
ret = -EIO;
|
||||
} else if (inode2 == NULL) {
|
||||
__ext4_error(inode1->i_sb, function,
|
||||
__ext4_error(inode1->i_sb, function, line,
|
||||
"Both inodes should not be NULL: "
|
||||
"inode1 %lu inode2 NULL", inode1->i_ino);
|
||||
ret = -EIO;
|
||||
|
@ -1084,7 +1084,7 @@ mext_inode_double_lock(struct inode *inode1, struct inode *inode2)
|
|||
|
||||
BUG_ON(inode1 == NULL && inode2 == NULL);
|
||||
|
||||
ret = mext_check_null_inode(inode1, inode2, __func__);
|
||||
ret = mext_check_null_inode(inode1, inode2, __func__, __LINE__);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
|
@ -1121,7 +1121,7 @@ mext_inode_double_unlock(struct inode *inode1, struct inode *inode2)
|
|||
|
||||
BUG_ON(inode1 == NULL && inode2 == NULL);
|
||||
|
||||
ret = mext_check_null_inode(inode1, inode2, __func__);
|
||||
ret = mext_check_null_inode(inode1, inode2, __func__, __LINE__);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
|
|
|
@ -179,30 +179,6 @@ static struct buffer_head * ext4_dx_find_entry(struct inode *dir,
|
|||
static int ext4_dx_add_entry(handle_t *handle, struct dentry *dentry,
|
||||
struct inode *inode);
|
||||
|
||||
unsigned int ext4_rec_len_from_disk(__le16 dlen, unsigned blocksize)
|
||||
{
|
||||
unsigned len = le16_to_cpu(dlen);
|
||||
|
||||
if (len == EXT4_MAX_REC_LEN || len == 0)
|
||||
return blocksize;
|
||||
return (len & 65532) | ((len & 3) << 16);
|
||||
}
|
||||
|
||||
__le16 ext4_rec_len_to_disk(unsigned len, unsigned blocksize)
|
||||
{
|
||||
if ((len > blocksize) || (blocksize > (1 << 18)) || (len & 3))
|
||||
BUG();
|
||||
if (len < 65536)
|
||||
return cpu_to_le16(len);
|
||||
if (len == blocksize) {
|
||||
if (blocksize == 65536)
|
||||
return cpu_to_le16(EXT4_MAX_REC_LEN);
|
||||
else
|
||||
return cpu_to_le16(0);
|
||||
}
|
||||
return cpu_to_le16((len & 65532) | ((len >> 16) & 3));
|
||||
}
|
||||
|
||||
/*
|
||||
* p is at least 6 bytes before the end of page
|
||||
*/
|
||||
|
@ -605,7 +581,7 @@ static int htree_dirblock_to_tree(struct file *dir_file,
|
|||
dir->i_sb->s_blocksize -
|
||||
EXT4_DIR_REC_LEN(0));
|
||||
for (; de < top; de = ext4_next_entry(de, dir->i_sb->s_blocksize)) {
|
||||
if (!ext4_check_dir_entry("htree_dirblock_to_tree", dir, de, bh,
|
||||
if (!ext4_check_dir_entry(dir, de, bh,
|
||||
(block<<EXT4_BLOCK_SIZE_BITS(dir->i_sb))
|
||||
+((char *)de - bh->b_data))) {
|
||||
/* On error, skip the f_pos to the next block. */
|
||||
|
@ -844,8 +820,7 @@ static inline int search_dirblock(struct buffer_head *bh,
|
|||
if ((char *) de + namelen <= dlimit &&
|
||||
ext4_match (namelen, name, de)) {
|
||||
/* found a match - just to be sure, do a full check */
|
||||
if (!ext4_check_dir_entry("ext4_find_entry",
|
||||
dir, de, bh, offset))
|
||||
if (!ext4_check_dir_entry(dir, de, bh, offset))
|
||||
return -1;
|
||||
*res_dir = de;
|
||||
return 1;
|
||||
|
@ -1019,7 +994,7 @@ static struct buffer_head * ext4_dx_find_entry(struct inode *dir, const struct q
|
|||
int off = (block << EXT4_BLOCK_SIZE_BITS(sb))
|
||||
+ ((char *) de - bh->b_data);
|
||||
|
||||
if (!ext4_check_dir_entry(__func__, dir, de, bh, off)) {
|
||||
if (!ext4_check_dir_entry(dir, de, bh, off)) {
|
||||
brelse(bh);
|
||||
*err = ERR_BAD_DX_DIR;
|
||||
goto errout;
|
||||
|
@ -1088,7 +1063,6 @@ static struct dentry *ext4_lookup(struct inode *dir, struct dentry *dentry, stru
|
|||
struct dentry *ext4_get_parent(struct dentry *child)
|
||||
{
|
||||
__u32 ino;
|
||||
struct inode *inode;
|
||||
static const struct qstr dotdot = {
|
||||
.name = "..",
|
||||
.len = 2,
|
||||
|
@ -1097,7 +1071,6 @@ struct dentry *ext4_get_parent(struct dentry *child)
|
|||
struct buffer_head *bh;
|
||||
|
||||
bh = ext4_find_entry(child->d_inode, &dotdot, &de);
|
||||
inode = NULL;
|
||||
if (!bh)
|
||||
return ERR_PTR(-ENOENT);
|
||||
ino = le32_to_cpu(de->inode);
|
||||
|
@ -1305,8 +1278,7 @@ static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry,
|
|||
de = (struct ext4_dir_entry_2 *)bh->b_data;
|
||||
top = bh->b_data + blocksize - reclen;
|
||||
while ((char *) de <= top) {
|
||||
if (!ext4_check_dir_entry("ext4_add_entry", dir, de,
|
||||
bh, offset))
|
||||
if (!ext4_check_dir_entry(dir, de, bh, offset))
|
||||
return -EIO;
|
||||
if (ext4_match(namelen, name, de))
|
||||
return -EEXIST;
|
||||
|
@ -1673,7 +1645,7 @@ static int ext4_delete_entry(handle_t *handle,
|
|||
pde = NULL;
|
||||
de = (struct ext4_dir_entry_2 *) bh->b_data;
|
||||
while (i < bh->b_size) {
|
||||
if (!ext4_check_dir_entry("ext4_delete_entry", dir, de, bh, i))
|
||||
if (!ext4_check_dir_entry(dir, de, bh, i))
|
||||
return -EIO;
|
||||
if (de == de_del) {
|
||||
BUFFER_TRACE(bh, "get_write_access");
|
||||
|
@ -1956,7 +1928,7 @@ static int empty_dir(struct inode *inode)
|
|||
}
|
||||
de = (struct ext4_dir_entry_2 *) bh->b_data;
|
||||
}
|
||||
if (!ext4_check_dir_entry("empty_dir", inode, de, bh, offset)) {
|
||||
if (!ext4_check_dir_entry(inode, de, bh, offset)) {
|
||||
de = (struct ext4_dir_entry_2 *)(bh->b_data +
|
||||
sb->s_blocksize);
|
||||
offset = (offset | (sb->s_blocksize - 1)) + 1;
|
||||
|
|
|
@ -921,8 +921,7 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input)
|
|||
&sbi->s_flex_groups[flex_group].free_inodes);
|
||||
}
|
||||
|
||||
ext4_handle_dirty_metadata(handle, NULL, sbi->s_sbh);
|
||||
sb->s_dirt = 1;
|
||||
ext4_handle_dirty_super(handle, sb);
|
||||
|
||||
exit_journal:
|
||||
mutex_unlock(&sbi->s_resize_lock);
|
||||
|
@ -953,7 +952,6 @@ int ext4_group_extend(struct super_block *sb, struct ext4_super_block *es,
|
|||
ext4_fsblk_t n_blocks_count)
|
||||
{
|
||||
ext4_fsblk_t o_blocks_count;
|
||||
ext4_group_t o_groups_count;
|
||||
ext4_grpblk_t last;
|
||||
ext4_grpblk_t add;
|
||||
struct buffer_head *bh;
|
||||
|
@ -965,7 +963,6 @@ int ext4_group_extend(struct super_block *sb, struct ext4_super_block *es,
|
|||
* yet: we're going to revalidate es->s_blocks_count after
|
||||
* taking the s_resize_lock below. */
|
||||
o_blocks_count = ext4_blocks_count(es);
|
||||
o_groups_count = EXT4_SB(sb)->s_groups_count;
|
||||
|
||||
if (test_opt(sb, DEBUG))
|
||||
printk(KERN_DEBUG "EXT4-fs: extending last group from %llu uto %llu blocks\n",
|
||||
|
@ -1045,13 +1042,12 @@ int ext4_group_extend(struct super_block *sb, struct ext4_super_block *es,
|
|||
goto exit_put;
|
||||
}
|
||||
ext4_blocks_count_set(es, o_blocks_count + add);
|
||||
ext4_handle_dirty_metadata(handle, NULL, EXT4_SB(sb)->s_sbh);
|
||||
sb->s_dirt = 1;
|
||||
mutex_unlock(&EXT4_SB(sb)->s_resize_lock);
|
||||
ext4_debug("freeing blocks %llu through %llu\n", o_blocks_count,
|
||||
o_blocks_count + add);
|
||||
/* We add the blocks to the bitmap and set the group need init bit */
|
||||
ext4_add_groupblocks(handle, sb, o_blocks_count, add);
|
||||
ext4_handle_dirty_super(handle, sb);
|
||||
ext4_debug("freed blocks %llu through %llu\n", o_blocks_count,
|
||||
o_blocks_count + add);
|
||||
if ((err = ext4_journal_stop(handle)))
|
||||
|
|
334
fs/ext4/super.c
334
fs/ext4/super.c
|
@ -241,14 +241,14 @@ handle_t *ext4_journal_start_sb(struct super_block *sb, int nblocks)
|
|||
if (sb->s_flags & MS_RDONLY)
|
||||
return ERR_PTR(-EROFS);
|
||||
|
||||
vfs_check_frozen(sb, SB_FREEZE_WRITE);
|
||||
vfs_check_frozen(sb, SB_FREEZE_TRANS);
|
||||
/* Special case here: if the journal has aborted behind our
|
||||
* backs (eg. EIO in the commit thread), then we still need to
|
||||
* take the FS itself readonly cleanly. */
|
||||
journal = EXT4_SB(sb)->s_journal;
|
||||
if (journal) {
|
||||
if (is_journal_aborted(journal)) {
|
||||
ext4_abort(sb, __func__, "Detected aborted journal");
|
||||
ext4_abort(sb, "Detected aborted journal");
|
||||
return ERR_PTR(-EROFS);
|
||||
}
|
||||
return jbd2_journal_start(journal, nblocks);
|
||||
|
@ -262,7 +262,7 @@ handle_t *ext4_journal_start_sb(struct super_block *sb, int nblocks)
|
|||
* that sync() will call the filesystem's write_super callback if
|
||||
* appropriate.
|
||||
*/
|
||||
int __ext4_journal_stop(const char *where, handle_t *handle)
|
||||
int __ext4_journal_stop(const char *where, unsigned int line, handle_t *handle)
|
||||
{
|
||||
struct super_block *sb;
|
||||
int err;
|
||||
|
@ -279,12 +279,13 @@ int __ext4_journal_stop(const char *where, handle_t *handle)
|
|||
if (!err)
|
||||
err = rc;
|
||||
if (err)
|
||||
__ext4_std_error(sb, where, err);
|
||||
__ext4_std_error(sb, where, line, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
void ext4_journal_abort_handle(const char *caller, const char *err_fn,
|
||||
struct buffer_head *bh, handle_t *handle, int err)
|
||||
void ext4_journal_abort_handle(const char *caller, unsigned int line,
|
||||
const char *err_fn, struct buffer_head *bh,
|
||||
handle_t *handle, int err)
|
||||
{
|
||||
char nbuf[16];
|
||||
const char *errstr = ext4_decode_error(NULL, err, nbuf);
|
||||
|
@ -300,12 +301,47 @@ void ext4_journal_abort_handle(const char *caller, const char *err_fn,
|
|||
if (is_handle_aborted(handle))
|
||||
return;
|
||||
|
||||
printk(KERN_ERR "%s: aborting transaction: %s in %s\n",
|
||||
caller, errstr, err_fn);
|
||||
printk(KERN_ERR "%s:%d: aborting transaction: %s in %s\n",
|
||||
caller, line, errstr, err_fn);
|
||||
|
||||
jbd2_journal_abort_handle(handle);
|
||||
}
|
||||
|
||||
static void __save_error_info(struct super_block *sb, const char *func,
|
||||
unsigned int line)
|
||||
{
|
||||
struct ext4_super_block *es = EXT4_SB(sb)->s_es;
|
||||
|
||||
EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS;
|
||||
es->s_state |= cpu_to_le16(EXT4_ERROR_FS);
|
||||
es->s_last_error_time = cpu_to_le32(get_seconds());
|
||||
strncpy(es->s_last_error_func, func, sizeof(es->s_last_error_func));
|
||||
es->s_last_error_line = cpu_to_le32(line);
|
||||
if (!es->s_first_error_time) {
|
||||
es->s_first_error_time = es->s_last_error_time;
|
||||
strncpy(es->s_first_error_func, func,
|
||||
sizeof(es->s_first_error_func));
|
||||
es->s_first_error_line = cpu_to_le32(line);
|
||||
es->s_first_error_ino = es->s_last_error_ino;
|
||||
es->s_first_error_block = es->s_last_error_block;
|
||||
}
|
||||
/*
|
||||
* Start the daily error reporting function if it hasn't been
|
||||
* started already
|
||||
*/
|
||||
if (!es->s_error_count)
|
||||
mod_timer(&EXT4_SB(sb)->s_err_report, jiffies + 24*60*60*HZ);
|
||||
es->s_error_count = cpu_to_le32(le32_to_cpu(es->s_error_count) + 1);
|
||||
}
|
||||
|
||||
static void save_error_info(struct super_block *sb, const char *func,
|
||||
unsigned int line)
|
||||
{
|
||||
__save_error_info(sb, func, line);
|
||||
ext4_commit_super(sb, 1);
|
||||
}
|
||||
|
||||
|
||||
/* Deal with the reporting of failure conditions on a filesystem such as
|
||||
* inconsistencies detected or read IO failures.
|
||||
*
|
||||
|
@ -323,11 +359,6 @@ void ext4_journal_abort_handle(const char *caller, const char *err_fn,
|
|||
|
||||
static void ext4_handle_error(struct super_block *sb)
|
||||
{
|
||||
struct ext4_super_block *es = EXT4_SB(sb)->s_es;
|
||||
|
||||
EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS;
|
||||
es->s_state |= cpu_to_le16(EXT4_ERROR_FS);
|
||||
|
||||
if (sb->s_flags & MS_RDONLY)
|
||||
return;
|
||||
|
||||
|
@ -342,19 +373,19 @@ static void ext4_handle_error(struct super_block *sb)
|
|||
ext4_msg(sb, KERN_CRIT, "Remounting filesystem read-only");
|
||||
sb->s_flags |= MS_RDONLY;
|
||||
}
|
||||
ext4_commit_super(sb, 1);
|
||||
if (test_opt(sb, ERRORS_PANIC))
|
||||
panic("EXT4-fs (device %s): panic forced after error\n",
|
||||
sb->s_id);
|
||||
}
|
||||
|
||||
void __ext4_error(struct super_block *sb, const char *function,
|
||||
const char *fmt, ...)
|
||||
unsigned int line, const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
printk(KERN_CRIT "EXT4-fs error (device %s): %s: ", sb->s_id, function);
|
||||
printk(KERN_CRIT "EXT4-fs error (device %s): %s:%d: comm %s: ",
|
||||
sb->s_id, function, line, current->comm);
|
||||
vprintk(fmt, args);
|
||||
printk("\n");
|
||||
va_end(args);
|
||||
|
@ -362,14 +393,22 @@ void __ext4_error(struct super_block *sb, const char *function,
|
|||
ext4_handle_error(sb);
|
||||
}
|
||||
|
||||
void ext4_error_inode(const char *function, struct inode *inode,
|
||||
void ext4_error_inode(struct inode *inode, const char *function,
|
||||
unsigned int line, ext4_fsblk_t block,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
struct ext4_super_block *es = EXT4_SB(inode->i_sb)->s_es;
|
||||
|
||||
es->s_last_error_ino = cpu_to_le32(inode->i_ino);
|
||||
es->s_last_error_block = cpu_to_le64(block);
|
||||
save_error_info(inode->i_sb, function, line);
|
||||
va_start(args, fmt);
|
||||
printk(KERN_CRIT "EXT4-fs error (device %s): %s: inode #%lu: (comm %s) ",
|
||||
inode->i_sb->s_id, function, inode->i_ino, current->comm);
|
||||
printk(KERN_CRIT "EXT4-fs error (device %s): %s:%d: inode #%lu: ",
|
||||
inode->i_sb->s_id, function, line, inode->i_ino);
|
||||
if (block)
|
||||
printk("block %llu: ", block);
|
||||
printk("comm %s: ", current->comm);
|
||||
vprintk(fmt, args);
|
||||
printk("\n");
|
||||
va_end(args);
|
||||
|
@ -377,20 +416,26 @@ void ext4_error_inode(const char *function, struct inode *inode,
|
|||
ext4_handle_error(inode->i_sb);
|
||||
}
|
||||
|
||||
void ext4_error_file(const char *function, struct file *file,
|
||||
const char *fmt, ...)
|
||||
void ext4_error_file(struct file *file, const char *function,
|
||||
unsigned int line, const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
struct ext4_super_block *es;
|
||||
struct inode *inode = file->f_dentry->d_inode;
|
||||
char pathname[80], *path;
|
||||
|
||||
es = EXT4_SB(inode->i_sb)->s_es;
|
||||
es->s_last_error_ino = cpu_to_le32(inode->i_ino);
|
||||
save_error_info(inode->i_sb, function, line);
|
||||
va_start(args, fmt);
|
||||
path = d_path(&(file->f_path), pathname, sizeof(pathname));
|
||||
if (!path)
|
||||
path = "(unknown)";
|
||||
printk(KERN_CRIT
|
||||
"EXT4-fs error (device %s): %s: inode #%lu (comm %s path %s): ",
|
||||
inode->i_sb->s_id, function, inode->i_ino, current->comm, path);
|
||||
"EXT4-fs error (device %s): %s:%d: inode #%lu "
|
||||
"(comm %s path %s): ",
|
||||
inode->i_sb->s_id, function, line, inode->i_ino,
|
||||
current->comm, path);
|
||||
vprintk(fmt, args);
|
||||
printk("\n");
|
||||
va_end(args);
|
||||
|
@ -435,7 +480,8 @@ static const char *ext4_decode_error(struct super_block *sb, int errno,
|
|||
/* __ext4_std_error decodes expected errors from journaling functions
|
||||
* automatically and invokes the appropriate error response. */
|
||||
|
||||
void __ext4_std_error(struct super_block *sb, const char *function, int errno)
|
||||
void __ext4_std_error(struct super_block *sb, const char *function,
|
||||
unsigned int line, int errno)
|
||||
{
|
||||
char nbuf[16];
|
||||
const char *errstr;
|
||||
|
@ -448,8 +494,9 @@ void __ext4_std_error(struct super_block *sb, const char *function, int errno)
|
|||
return;
|
||||
|
||||
errstr = ext4_decode_error(sb, errno, nbuf);
|
||||
printk(KERN_CRIT "EXT4-fs error (device %s) in %s: %s\n",
|
||||
sb->s_id, function, errstr);
|
||||
printk(KERN_CRIT "EXT4-fs error (device %s) in %s:%d: %s\n",
|
||||
sb->s_id, function, line, errstr);
|
||||
save_error_info(sb, function, line);
|
||||
|
||||
ext4_handle_error(sb);
|
||||
}
|
||||
|
@ -464,29 +511,29 @@ void __ext4_std_error(struct super_block *sb, const char *function, int errno)
|
|||
* case we take the easy way out and panic immediately.
|
||||
*/
|
||||
|
||||
void ext4_abort(struct super_block *sb, const char *function,
|
||||
const char *fmt, ...)
|
||||
void __ext4_abort(struct super_block *sb, const char *function,
|
||||
unsigned int line, const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
save_error_info(sb, function, line);
|
||||
va_start(args, fmt);
|
||||
printk(KERN_CRIT "EXT4-fs error (device %s): %s: ", sb->s_id, function);
|
||||
printk(KERN_CRIT "EXT4-fs error (device %s): %s:%d: ", sb->s_id,
|
||||
function, line);
|
||||
vprintk(fmt, args);
|
||||
printk("\n");
|
||||
va_end(args);
|
||||
|
||||
if ((sb->s_flags & MS_RDONLY) == 0) {
|
||||
ext4_msg(sb, KERN_CRIT, "Remounting filesystem read-only");
|
||||
sb->s_flags |= MS_RDONLY;
|
||||
EXT4_SB(sb)->s_mount_flags |= EXT4_MF_FS_ABORTED;
|
||||
if (EXT4_SB(sb)->s_journal)
|
||||
jbd2_journal_abort(EXT4_SB(sb)->s_journal, -EIO);
|
||||
save_error_info(sb, function, line);
|
||||
}
|
||||
if (test_opt(sb, ERRORS_PANIC))
|
||||
panic("EXT4-fs panic from previous error\n");
|
||||
|
||||
if (sb->s_flags & MS_RDONLY)
|
||||
return;
|
||||
|
||||
ext4_msg(sb, KERN_CRIT, "Remounting filesystem read-only");
|
||||
EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS;
|
||||
sb->s_flags |= MS_RDONLY;
|
||||
EXT4_SB(sb)->s_mount_flags |= EXT4_MF_FS_ABORTED;
|
||||
if (EXT4_SB(sb)->s_journal)
|
||||
jbd2_journal_abort(EXT4_SB(sb)->s_journal, -EIO);
|
||||
}
|
||||
|
||||
void ext4_msg (struct super_block * sb, const char *prefix,
|
||||
|
@ -502,38 +549,47 @@ void ext4_msg (struct super_block * sb, const char *prefix,
|
|||
}
|
||||
|
||||
void __ext4_warning(struct super_block *sb, const char *function,
|
||||
const char *fmt, ...)
|
||||
unsigned int line, const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
printk(KERN_WARNING "EXT4-fs warning (device %s): %s: ",
|
||||
sb->s_id, function);
|
||||
printk(KERN_WARNING "EXT4-fs warning (device %s): %s:%d: ",
|
||||
sb->s_id, function, line);
|
||||
vprintk(fmt, args);
|
||||
printk("\n");
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void ext4_grp_locked_error(struct super_block *sb, ext4_group_t grp,
|
||||
const char *function, const char *fmt, ...)
|
||||
void __ext4_grp_locked_error(const char *function, unsigned int line,
|
||||
struct super_block *sb, ext4_group_t grp,
|
||||
unsigned long ino, ext4_fsblk_t block,
|
||||
const char *fmt, ...)
|
||||
__releases(bitlock)
|
||||
__acquires(bitlock)
|
||||
{
|
||||
va_list args;
|
||||
struct ext4_super_block *es = EXT4_SB(sb)->s_es;
|
||||
|
||||
es->s_last_error_ino = cpu_to_le32(ino);
|
||||
es->s_last_error_block = cpu_to_le64(block);
|
||||
__save_error_info(sb, function, line);
|
||||
va_start(args, fmt);
|
||||
printk(KERN_CRIT "EXT4-fs error (device %s): %s: ", sb->s_id, function);
|
||||
printk(KERN_CRIT "EXT4-fs error (device %s): %s:%d: group %u",
|
||||
sb->s_id, function, line, grp);
|
||||
if (ino)
|
||||
printk("inode %lu: ", ino);
|
||||
if (block)
|
||||
printk("block %llu:", (unsigned long long) block);
|
||||
vprintk(fmt, args);
|
||||
printk("\n");
|
||||
va_end(args);
|
||||
|
||||
if (test_opt(sb, ERRORS_CONT)) {
|
||||
EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS;
|
||||
es->s_state |= cpu_to_le16(EXT4_ERROR_FS);
|
||||
ext4_commit_super(sb, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
ext4_unlock_group(sb, grp);
|
||||
ext4_handle_error(sb);
|
||||
/*
|
||||
|
@ -660,8 +716,7 @@ static void ext4_put_super(struct super_block *sb)
|
|||
err = jbd2_journal_destroy(sbi->s_journal);
|
||||
sbi->s_journal = NULL;
|
||||
if (err < 0)
|
||||
ext4_abort(sb, __func__,
|
||||
"Couldn't clean up the journal");
|
||||
ext4_abort(sb, "Couldn't clean up the journal");
|
||||
}
|
||||
|
||||
ext4_release_system_zone(sb);
|
||||
|
@ -946,14 +1001,12 @@ static int ext4_show_options(struct seq_file *seq, struct vfsmount *vfs)
|
|||
seq_puts(seq, ",journal_async_commit");
|
||||
else if (test_opt(sb, JOURNAL_CHECKSUM))
|
||||
seq_puts(seq, ",journal_checksum");
|
||||
if (test_opt(sb, NOBH))
|
||||
seq_puts(seq, ",nobh");
|
||||
if (test_opt(sb, I_VERSION))
|
||||
seq_puts(seq, ",i_version");
|
||||
if (!test_opt(sb, DELALLOC))
|
||||
if (!test_opt(sb, DELALLOC) &&
|
||||
!(def_mount_opts & EXT4_DEFM_NODELALLOC))
|
||||
seq_puts(seq, ",nodelalloc");
|
||||
|
||||
|
||||
if (sbi->s_stripe)
|
||||
seq_printf(seq, ",stripe=%lu", sbi->s_stripe);
|
||||
/*
|
||||
|
@ -977,7 +1030,7 @@ static int ext4_show_options(struct seq_file *seq, struct vfsmount *vfs)
|
|||
if (test_opt(sb, NO_AUTO_DA_ALLOC))
|
||||
seq_puts(seq, ",noauto_da_alloc");
|
||||
|
||||
if (test_opt(sb, DISCARD))
|
||||
if (test_opt(sb, DISCARD) && !(def_mount_opts & EXT4_DEFM_DISCARD))
|
||||
seq_puts(seq, ",discard");
|
||||
|
||||
if (test_opt(sb, NOLOAD))
|
||||
|
@ -986,6 +1039,10 @@ static int ext4_show_options(struct seq_file *seq, struct vfsmount *vfs)
|
|||
if (test_opt(sb, DIOREAD_NOLOCK))
|
||||
seq_puts(seq, ",dioread_nolock");
|
||||
|
||||
if (test_opt(sb, BLOCK_VALIDITY) &&
|
||||
!(def_mount_opts & EXT4_DEFM_BLOCK_VALIDITY))
|
||||
seq_puts(seq, ",block_validity");
|
||||
|
||||
ext4_show_quota_options(seq, sb);
|
||||
|
||||
return 0;
|
||||
|
@ -1065,6 +1122,7 @@ static int ext4_mark_dquot_dirty(struct dquot *dquot);
|
|||
static int ext4_write_info(struct super_block *sb, int type);
|
||||
static int ext4_quota_on(struct super_block *sb, int type, int format_id,
|
||||
char *path);
|
||||
static int ext4_quota_off(struct super_block *sb, int type);
|
||||
static int ext4_quota_on_mount(struct super_block *sb, int type);
|
||||
static ssize_t ext4_quota_read(struct super_block *sb, int type, char *data,
|
||||
size_t len, loff_t off);
|
||||
|
@ -1086,7 +1144,7 @@ static const struct dquot_operations ext4_quota_operations = {
|
|||
|
||||
static const struct quotactl_ops ext4_qctl_operations = {
|
||||
.quota_on = ext4_quota_on,
|
||||
.quota_off = dquot_quota_off,
|
||||
.quota_off = ext4_quota_off,
|
||||
.quota_sync = dquot_quota_sync,
|
||||
.get_info = dquot_get_dqinfo,
|
||||
.set_info = dquot_set_dqinfo,
|
||||
|
@ -1624,10 +1682,12 @@ set_qf_format:
|
|||
*n_blocks_count = option;
|
||||
break;
|
||||
case Opt_nobh:
|
||||
set_opt(sbi->s_mount_opt, NOBH);
|
||||
ext4_msg(sb, KERN_WARNING,
|
||||
"Ignoring deprecated nobh option");
|
||||
break;
|
||||
case Opt_bh:
|
||||
clear_opt(sbi->s_mount_opt, NOBH);
|
||||
ext4_msg(sb, KERN_WARNING,
|
||||
"Ignoring deprecated bh option");
|
||||
break;
|
||||
case Opt_i_version:
|
||||
set_opt(sbi->s_mount_opt, I_VERSION);
|
||||
|
@ -2249,6 +2309,8 @@ static ssize_t session_write_kbytes_show(struct ext4_attr *a,
|
|||
{
|
||||
struct super_block *sb = sbi->s_buddy_cache->i_sb;
|
||||
|
||||
if (!sb->s_bdev->bd_part)
|
||||
return snprintf(buf, PAGE_SIZE, "0\n");
|
||||
return snprintf(buf, PAGE_SIZE, "%lu\n",
|
||||
(part_stat_read(sb->s_bdev->bd_part, sectors[1]) -
|
||||
sbi->s_sectors_written_start) >> 1);
|
||||
|
@ -2259,6 +2321,8 @@ static ssize_t lifetime_write_kbytes_show(struct ext4_attr *a,
|
|||
{
|
||||
struct super_block *sb = sbi->s_buddy_cache->i_sb;
|
||||
|
||||
if (!sb->s_bdev->bd_part)
|
||||
return snprintf(buf, PAGE_SIZE, "0\n");
|
||||
return snprintf(buf, PAGE_SIZE, "%llu\n",
|
||||
(unsigned long long)(sbi->s_kbytes_written +
|
||||
((part_stat_read(sb->s_bdev->bd_part, sectors[1]) -
|
||||
|
@ -2431,6 +2495,53 @@ static int ext4_feature_set_ok(struct super_block *sb, int readonly)
|
|||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is called once a day if we have errors logged
|
||||
* on the file system
|
||||
*/
|
||||
static void print_daily_error_info(unsigned long arg)
|
||||
{
|
||||
struct super_block *sb = (struct super_block *) arg;
|
||||
struct ext4_sb_info *sbi;
|
||||
struct ext4_super_block *es;
|
||||
|
||||
sbi = EXT4_SB(sb);
|
||||
es = sbi->s_es;
|
||||
|
||||
if (es->s_error_count)
|
||||
ext4_msg(sb, KERN_NOTICE, "error count: %u",
|
||||
le32_to_cpu(es->s_error_count));
|
||||
if (es->s_first_error_time) {
|
||||
printk(KERN_NOTICE "EXT4-fs (%s): initial error at %u: %.*s:%d",
|
||||
sb->s_id, le32_to_cpu(es->s_first_error_time),
|
||||
(int) sizeof(es->s_first_error_func),
|
||||
es->s_first_error_func,
|
||||
le32_to_cpu(es->s_first_error_line));
|
||||
if (es->s_first_error_ino)
|
||||
printk(": inode %u",
|
||||
le32_to_cpu(es->s_first_error_ino));
|
||||
if (es->s_first_error_block)
|
||||
printk(": block %llu", (unsigned long long)
|
||||
le64_to_cpu(es->s_first_error_block));
|
||||
printk("\n");
|
||||
}
|
||||
if (es->s_last_error_time) {
|
||||
printk(KERN_NOTICE "EXT4-fs (%s): last error at %u: %.*s:%d",
|
||||
sb->s_id, le32_to_cpu(es->s_last_error_time),
|
||||
(int) sizeof(es->s_last_error_func),
|
||||
es->s_last_error_func,
|
||||
le32_to_cpu(es->s_last_error_line));
|
||||
if (es->s_last_error_ino)
|
||||
printk(": inode %u",
|
||||
le32_to_cpu(es->s_last_error_ino));
|
||||
if (es->s_last_error_block)
|
||||
printk(": block %llu", (unsigned long long)
|
||||
le64_to_cpu(es->s_last_error_block));
|
||||
printk("\n");
|
||||
}
|
||||
mod_timer(&sbi->s_err_report, jiffies + 24*60*60*HZ); /* Once a day */
|
||||
}
|
||||
|
||||
static int ext4_fill_super(struct super_block *sb, void *data, int silent)
|
||||
__releases(kernel_lock)
|
||||
__acquires(kernel_lock)
|
||||
|
@ -2448,7 +2559,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
|
|||
struct inode *root;
|
||||
char *cp;
|
||||
const char *descr;
|
||||
int ret = -EINVAL;
|
||||
int ret = -ENOMEM;
|
||||
int blocksize;
|
||||
unsigned int db_count;
|
||||
unsigned int i;
|
||||
|
@ -2459,13 +2570,13 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
|
|||
|
||||
sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
|
||||
if (!sbi)
|
||||
return -ENOMEM;
|
||||
goto out_free_orig;
|
||||
|
||||
sbi->s_blockgroup_lock =
|
||||
kzalloc(sizeof(struct blockgroup_lock), GFP_KERNEL);
|
||||
if (!sbi->s_blockgroup_lock) {
|
||||
kfree(sbi);
|
||||
return -ENOMEM;
|
||||
goto out_free_orig;
|
||||
}
|
||||
sb->s_fs_info = sbi;
|
||||
sbi->s_mount_opt = 0;
|
||||
|
@ -2473,8 +2584,9 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
|
|||
sbi->s_resgid = EXT4_DEF_RESGID;
|
||||
sbi->s_inode_readahead_blks = EXT4_DEF_INODE_READAHEAD_BLKS;
|
||||
sbi->s_sb_block = sb_block;
|
||||
sbi->s_sectors_written_start = part_stat_read(sb->s_bdev->bd_part,
|
||||
sectors[1]);
|
||||
if (sb->s_bdev->bd_part)
|
||||
sbi->s_sectors_written_start =
|
||||
part_stat_read(sb->s_bdev->bd_part, sectors[1]);
|
||||
|
||||
unlock_kernel();
|
||||
|
||||
|
@ -2482,6 +2594,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
|
|||
for (cp = sb->s_id; (cp = strchr(cp, '/'));)
|
||||
*cp = '!';
|
||||
|
||||
ret = -EINVAL;
|
||||
blocksize = sb_min_blocksize(sb, EXT4_MIN_BLOCK_SIZE);
|
||||
if (!blocksize) {
|
||||
ext4_msg(sb, KERN_ERR, "unable to set blocksize");
|
||||
|
@ -2546,6 +2659,10 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
|
|||
set_opt(sbi->s_mount_opt, ERRORS_CONT);
|
||||
else
|
||||
set_opt(sbi->s_mount_opt, ERRORS_RO);
|
||||
if (def_mount_opts & EXT4_DEFM_BLOCK_VALIDITY)
|
||||
set_opt(sbi->s_mount_opt, BLOCK_VALIDITY);
|
||||
if (def_mount_opts & EXT4_DEFM_DISCARD)
|
||||
set_opt(sbi->s_mount_opt, DISCARD);
|
||||
|
||||
sbi->s_resuid = le16_to_cpu(es->s_def_resuid);
|
||||
sbi->s_resgid = le16_to_cpu(es->s_def_resgid);
|
||||
|
@ -2553,15 +2670,23 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
|
|||
sbi->s_min_batch_time = EXT4_DEF_MIN_BATCH_TIME;
|
||||
sbi->s_max_batch_time = EXT4_DEF_MAX_BATCH_TIME;
|
||||
|
||||
set_opt(sbi->s_mount_opt, BARRIER);
|
||||
if ((def_mount_opts & EXT4_DEFM_NOBARRIER) == 0)
|
||||
set_opt(sbi->s_mount_opt, BARRIER);
|
||||
|
||||
/*
|
||||
* enable delayed allocation by default
|
||||
* Use -o nodelalloc to turn it off
|
||||
*/
|
||||
if (!IS_EXT3_SB(sb))
|
||||
if (!IS_EXT3_SB(sb) &&
|
||||
((def_mount_opts & EXT4_DEFM_NODELALLOC) == 0))
|
||||
set_opt(sbi->s_mount_opt, DELALLOC);
|
||||
|
||||
if (!parse_options((char *) sbi->s_es->s_mount_opts, sb,
|
||||
&journal_devnum, &journal_ioprio, NULL, 0)) {
|
||||
ext4_msg(sb, KERN_WARNING,
|
||||
"failed to parse options in superblock: %s",
|
||||
sbi->s_es->s_mount_opts);
|
||||
}
|
||||
if (!parse_options((char *) data, sb, &journal_devnum,
|
||||
&journal_ioprio, NULL, 0))
|
||||
goto failed_mount;
|
||||
|
@ -2912,18 +3037,7 @@ no_journal:
|
|||
ext4_msg(sb, KERN_ERR, "insufficient memory");
|
||||
goto failed_mount_wq;
|
||||
}
|
||||
if (test_opt(sb, NOBH)) {
|
||||
if (!(test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_WRITEBACK_DATA)) {
|
||||
ext4_msg(sb, KERN_WARNING, "Ignoring nobh option - "
|
||||
"its supported only with writeback mode");
|
||||
clear_opt(sbi->s_mount_opt, NOBH);
|
||||
}
|
||||
if (test_opt(sb, DIOREAD_NOLOCK)) {
|
||||
ext4_msg(sb, KERN_WARNING, "dioread_nolock option is "
|
||||
"not supported with nobh mode");
|
||||
goto failed_mount_wq;
|
||||
}
|
||||
}
|
||||
|
||||
EXT4_SB(sb)->dio_unwritten_wq = create_workqueue("ext4-dio-unwritten");
|
||||
if (!EXT4_SB(sb)->dio_unwritten_wq) {
|
||||
printk(KERN_ERR "EXT4-fs: failed to create DIO workqueue\n");
|
||||
|
@ -3043,7 +3157,14 @@ no_journal:
|
|||
descr = "out journal";
|
||||
|
||||
ext4_msg(sb, KERN_INFO, "mounted filesystem with%s. "
|
||||
"Opts: %s", descr, orig_data);
|
||||
"Opts: %s%s%s", descr, sbi->s_es->s_mount_opts,
|
||||
*sbi->s_es->s_mount_opts ? "; " : "", orig_data);
|
||||
|
||||
init_timer(&sbi->s_err_report);
|
||||
sbi->s_err_report.function = print_daily_error_info;
|
||||
sbi->s_err_report.data = (unsigned long) sb;
|
||||
if (es->s_error_count)
|
||||
mod_timer(&sbi->s_err_report, jiffies + 300*HZ); /* 5 minutes */
|
||||
|
||||
lock_kernel();
|
||||
kfree(orig_data);
|
||||
|
@ -3093,6 +3214,7 @@ out_fail:
|
|||
kfree(sbi->s_blockgroup_lock);
|
||||
kfree(sbi);
|
||||
lock_kernel();
|
||||
out_free_orig:
|
||||
kfree(orig_data);
|
||||
return ret;
|
||||
}
|
||||
|
@ -3110,7 +3232,7 @@ static void ext4_init_journal_params(struct super_block *sb, journal_t *journal)
|
|||
journal->j_min_batch_time = sbi->s_min_batch_time;
|
||||
journal->j_max_batch_time = sbi->s_max_batch_time;
|
||||
|
||||
spin_lock(&journal->j_state_lock);
|
||||
write_lock(&journal->j_state_lock);
|
||||
if (test_opt(sb, BARRIER))
|
||||
journal->j_flags |= JBD2_BARRIER;
|
||||
else
|
||||
|
@ -3119,7 +3241,7 @@ static void ext4_init_journal_params(struct super_block *sb, journal_t *journal)
|
|||
journal->j_flags |= JBD2_ABORT_ON_SYNCDATA_ERR;
|
||||
else
|
||||
journal->j_flags &= ~JBD2_ABORT_ON_SYNCDATA_ERR;
|
||||
spin_unlock(&journal->j_state_lock);
|
||||
write_unlock(&journal->j_state_lock);
|
||||
}
|
||||
|
||||
static journal_t *ext4_get_journal(struct super_block *sb,
|
||||
|
@ -3327,8 +3449,17 @@ static int ext4_load_journal(struct super_block *sb,
|
|||
|
||||
if (!EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER))
|
||||
err = jbd2_journal_wipe(journal, !really_read_only);
|
||||
if (!err)
|
||||
if (!err) {
|
||||
char *save = kmalloc(EXT4_S_ERR_LEN, GFP_KERNEL);
|
||||
if (save)
|
||||
memcpy(save, ((char *) es) +
|
||||
EXT4_S_ERR_START, EXT4_S_ERR_LEN);
|
||||
err = jbd2_journal_load(journal);
|
||||
if (save)
|
||||
memcpy(((char *) es) + EXT4_S_ERR_START,
|
||||
save, EXT4_S_ERR_LEN);
|
||||
kfree(save);
|
||||
}
|
||||
|
||||
if (err) {
|
||||
ext4_msg(sb, KERN_ERR, "error loading journal");
|
||||
|
@ -3384,10 +3515,14 @@ static int ext4_commit_super(struct super_block *sb, int sync)
|
|||
*/
|
||||
if (!(sb->s_flags & MS_RDONLY))
|
||||
es->s_wtime = cpu_to_le32(get_seconds());
|
||||
es->s_kbytes_written =
|
||||
cpu_to_le64(EXT4_SB(sb)->s_kbytes_written +
|
||||
if (sb->s_bdev->bd_part)
|
||||
es->s_kbytes_written =
|
||||
cpu_to_le64(EXT4_SB(sb)->s_kbytes_written +
|
||||
((part_stat_read(sb->s_bdev->bd_part, sectors[1]) -
|
||||
EXT4_SB(sb)->s_sectors_written_start) >> 1));
|
||||
else
|
||||
es->s_kbytes_written =
|
||||
cpu_to_le64(EXT4_SB(sb)->s_kbytes_written);
|
||||
ext4_free_blocks_count_set(es, percpu_counter_sum_positive(
|
||||
&EXT4_SB(sb)->s_freeblocks_counter));
|
||||
es->s_free_inodes_count = cpu_to_le32(percpu_counter_sum_positive(
|
||||
|
@ -3491,7 +3626,7 @@ int ext4_force_commit(struct super_block *sb)
|
|||
|
||||
journal = EXT4_SB(sb)->s_journal;
|
||||
if (journal) {
|
||||
vfs_check_frozen(sb, SB_FREEZE_WRITE);
|
||||
vfs_check_frozen(sb, SB_FREEZE_TRANS);
|
||||
ret = ext4_journal_force_commit(journal);
|
||||
}
|
||||
|
||||
|
@ -3616,7 +3751,7 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
|
|||
}
|
||||
|
||||
if (sbi->s_mount_flags & EXT4_MF_FS_ABORTED)
|
||||
ext4_abort(sb, __func__, "Abort forced by user");
|
||||
ext4_abort(sb, "Abort forced by user");
|
||||
|
||||
sb->s_flags = (sb->s_flags & ~MS_POSIXACL) |
|
||||
(test_opt(sb, POSIX_ACL) ? MS_POSIXACL : 0);
|
||||
|
@ -3981,6 +4116,18 @@ static int ext4_quota_on(struct super_block *sb, int type, int format_id,
|
|||
return err;
|
||||
}
|
||||
|
||||
static int ext4_quota_off(struct super_block *sb, int type)
|
||||
{
|
||||
/* Force all delayed allocation blocks to be allocated */
|
||||
if (test_opt(sb, DELALLOC)) {
|
||||
down_read(&sb->s_umount);
|
||||
sync_filesystem(sb);
|
||||
up_read(&sb->s_umount);
|
||||
}
|
||||
|
||||
return dquot_quota_off(sb, type);
|
||||
}
|
||||
|
||||
/* Read data from quotafile - avoid pagecache and such because we cannot afford
|
||||
* acquiring the locks... As quota files are never truncated and quota code
|
||||
* itself serializes the operations (and noone else should touch the files)
|
||||
|
@ -4030,7 +4177,6 @@ static ssize_t ext4_quota_write(struct super_block *sb, int type,
|
|||
ext4_lblk_t blk = off >> EXT4_BLOCK_SIZE_BITS(sb);
|
||||
int err = 0;
|
||||
int offset = off & (sb->s_blocksize - 1);
|
||||
int journal_quota = EXT4_SB(sb)->s_qf_names[type] != NULL;
|
||||
struct buffer_head *bh;
|
||||
handle_t *handle = journal_current_handle();
|
||||
|
||||
|
@ -4055,24 +4201,16 @@ static ssize_t ext4_quota_write(struct super_block *sb, int type,
|
|||
bh = ext4_bread(handle, inode, blk, 1, &err);
|
||||
if (!bh)
|
||||
goto out;
|
||||
if (journal_quota) {
|
||||
err = ext4_journal_get_write_access(handle, bh);
|
||||
if (err) {
|
||||
brelse(bh);
|
||||
goto out;
|
||||
}
|
||||
err = ext4_journal_get_write_access(handle, bh);
|
||||
if (err) {
|
||||
brelse(bh);
|
||||
goto out;
|
||||
}
|
||||
lock_buffer(bh);
|
||||
memcpy(bh->b_data+offset, data, len);
|
||||
flush_dcache_page(bh->b_page);
|
||||
unlock_buffer(bh);
|
||||
if (journal_quota)
|
||||
err = ext4_handle_dirty_metadata(handle, NULL, bh);
|
||||
else {
|
||||
/* Always do at least ordered writes for quotas */
|
||||
err = ext4_jbd2_file_inode(handle, inode);
|
||||
mark_buffer_dirty(bh);
|
||||
}
|
||||
err = ext4_handle_dirty_metadata(handle, NULL, bh);
|
||||
brelse(bh);
|
||||
out:
|
||||
if (err) {
|
||||
|
|
|
@ -458,8 +458,7 @@ static void ext4_xattr_update_super_block(handle_t *handle,
|
|||
|
||||
if (ext4_journal_get_write_access(handle, EXT4_SB(sb)->s_sbh) == 0) {
|
||||
EXT4_SET_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_EXT_ATTR);
|
||||
sb->s_dirt = 1;
|
||||
ext4_handle_dirty_metadata(handle, NULL, EXT4_SB(sb)->s_sbh);
|
||||
ext4_handle_dirty_super(handle, sb);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue