summaryrefslogtreecommitdiffstats
path: root/fs/ext3
diff options
context:
space:
mode:
Diffstat (limited to 'fs/ext3')
-rw-r--r--fs/ext3/balloc.c40
-rw-r--r--fs/ext3/bitmap.c6
-rw-r--r--fs/ext3/dir.c52
-rw-r--r--fs/ext3/file.c4
-rw-r--r--fs/ext3/inode.c16
-rw-r--r--fs/ext3/ioctl.c4
-rw-r--r--fs/ext3/super.c16
7 files changed, 81 insertions, 57 deletions
diff --git a/fs/ext3/balloc.c b/fs/ext3/balloc.c
index 6250fcdf14a..46623f77666 100644
--- a/fs/ext3/balloc.c
+++ b/fs/ext3/balloc.c
@@ -1493,12 +1493,33 @@ static int ext3_group_sparse(int group)
*/
int ext3_bg_has_super(struct super_block *sb, int group)
{
- if (EXT3_HAS_RO_COMPAT_FEATURE(sb,EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER)&&
- !ext3_group_sparse(group))
+ if (EXT3_HAS_RO_COMPAT_FEATURE(sb,
+ EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER) &&
+ !ext3_group_sparse(group))
return 0;
return 1;
}
+static unsigned long ext3_bg_num_gdb_meta(struct super_block *sb, int group)
+{
+ unsigned long metagroup = group / EXT3_DESC_PER_BLOCK(sb);
+ unsigned long first = metagroup * EXT3_DESC_PER_BLOCK(sb);
+ unsigned long last = first + EXT3_DESC_PER_BLOCK(sb) - 1;
+
+ if (group == first || group == first + 1 || group == last)
+ return 1;
+ return 0;
+}
+
+static unsigned long ext3_bg_num_gdb_nometa(struct super_block *sb, int group)
+{
+ if (EXT3_HAS_RO_COMPAT_FEATURE(sb,
+ EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER) &&
+ !ext3_group_sparse(group))
+ return 0;
+ return EXT3_SB(sb)->s_gdb_count;
+}
+
/**
* ext3_bg_num_gdb - number of blocks used by the group table in group
* @sb: superblock for filesystem
@@ -1510,9 +1531,14 @@ int ext3_bg_has_super(struct super_block *sb, int group)
*/
unsigned long ext3_bg_num_gdb(struct super_block *sb, int group)
{
- if (EXT3_HAS_RO_COMPAT_FEATURE(sb,EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER)&&
- !ext3_group_sparse(group))
- return 0;
- return EXT3_SB(sb)->s_gdb_count;
-}
+ unsigned long first_meta_bg =
+ le32_to_cpu(EXT3_SB(sb)->s_es->s_first_meta_bg);
+ unsigned long metagroup = group / EXT3_DESC_PER_BLOCK(sb);
+
+ if (!EXT3_HAS_INCOMPAT_FEATURE(sb,EXT3_FEATURE_INCOMPAT_META_BG) ||
+ metagroup < first_meta_bg)
+ return ext3_bg_num_gdb_nometa(sb,group);
+ return ext3_bg_num_gdb_meta(sb,group);
+
+}
diff --git a/fs/ext3/bitmap.c b/fs/ext3/bitmap.c
index cb16b4c5d5d..ce4f82b9e52 100644
--- a/fs/ext3/bitmap.c
+++ b/fs/ext3/bitmap.c
@@ -7,11 +7,11 @@
* Universite Pierre et Marie Curie (Paris VI)
*/
-#ifdef EXT3FS_DEBUG
-
#include <linux/buffer_head.h>
+#include <linux/jbd.h>
+#include <linux/ext3_fs.h>
-#include "ext3_fs.h"
+#ifdef EXT3FS_DEBUG
static int nibblemap[] = {4, 3, 3, 2, 3, 2, 2, 1, 3, 2, 2, 1, 2, 1, 1, 0};
diff --git a/fs/ext3/dir.c b/fs/ext3/dir.c
index 832867aef3d..773459164bb 100644
--- a/fs/ext3/dir.c
+++ b/fs/ext3/dir.c
@@ -95,11 +95,10 @@ static int ext3_readdir(struct file * filp,
void * dirent, filldir_t filldir)
{
int error = 0;
- unsigned long offset, blk;
- int i, num, stored;
- struct buffer_head * bh, * tmp, * bha[16];
- struct ext3_dir_entry_2 * de;
- struct super_block * sb;
+ unsigned long offset;
+ int i, stored;
+ struct ext3_dir_entry_2 *de;
+ struct super_block *sb;
int err;
struct inode *inode = filp->f_dentry->d_inode;
int ret = 0;
@@ -124,12 +123,29 @@ static int ext3_readdir(struct file * filp,
}
#endif
stored = 0;
- bh = NULL;
offset = filp->f_pos & (sb->s_blocksize - 1);
while (!error && !stored && filp->f_pos < inode->i_size) {
- blk = (filp->f_pos) >> EXT3_BLOCK_SIZE_BITS(sb);
- bh = ext3_bread(NULL, inode, blk, 0, &err);
+ unsigned long blk = filp->f_pos >> EXT3_BLOCK_SIZE_BITS(sb);
+ struct buffer_head map_bh;
+ struct buffer_head *bh = NULL;
+
+ map_bh.b_state = 0;
+ err = ext3_get_block_handle(NULL, inode, blk, &map_bh, 0, 0);
+ if (!err) {
+ page_cache_readahead(sb->s_bdev->bd_inode->i_mapping,
+ &filp->f_ra,
+ filp,
+ map_bh.b_blocknr >>
+ (PAGE_CACHE_SHIFT - inode->i_blkbits),
+ 1);
+ bh = ext3_bread(NULL, inode, blk, 0, &err);
+ }
+
+ /*
+ * We ignore I/O errors on directories so users have a chance
+ * of recovering data when there's a bad sector
+ */
if (!bh) {
ext3_error (sb, "ext3_readdir",
"directory #%lu contains a hole at offset %lu",
@@ -138,26 +154,6 @@ static int ext3_readdir(struct file * filp,
continue;
}
- /*
- * Do the readahead
- */
- if (!offset) {
- for (i = 16 >> (EXT3_BLOCK_SIZE_BITS(sb) - 9), num = 0;
- i > 0; i--) {
- tmp = ext3_getblk (NULL, inode, ++blk, 0, &err);
- if (tmp && !buffer_uptodate(tmp) &&
- !buffer_locked(tmp))
- bha[num++] = tmp;
- else
- brelse (tmp);
- }
- if (num) {
- ll_rw_block (READA, num, bha);
- for (i = 0; i < num; i++)
- brelse (bha[i]);
- }
- }
-
revalidate:
/* If the dir block has changed since the last call to
* readdir(2), then we might be pointing to an invalid
diff --git a/fs/ext3/file.c b/fs/ext3/file.c
index 98e78345ead..59098ea5671 100644
--- a/fs/ext3/file.c
+++ b/fs/ext3/file.c
@@ -37,9 +37,9 @@ static int ext3_release_file (struct inode * inode, struct file * filp)
if ((filp->f_mode & FMODE_WRITE) &&
(atomic_read(&inode->i_writecount) == 1))
{
- down(&EXT3_I(inode)->truncate_sem);
+ mutex_lock(&EXT3_I(inode)->truncate_mutex);
ext3_discard_reservation(inode);
- up(&EXT3_I(inode)->truncate_sem);
+ mutex_unlock(&EXT3_I(inode)->truncate_mutex);
}
if (is_dx(inode) && filp->private_data)
ext3_htree_free_dir_info(filp->private_data);
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c
index 0384e539b88..2c361377e0a 100644
--- a/fs/ext3/inode.c
+++ b/fs/ext3/inode.c
@@ -671,7 +671,7 @@ err_out:
* The BKL may not be held on entry here. Be sure to take it early.
*/
-static int
+int
ext3_get_block_handle(handle_t *handle, struct inode *inode, sector_t iblock,
struct buffer_head *bh_result, int create, int extend_disksize)
{
@@ -702,7 +702,7 @@ ext3_get_block_handle(handle_t *handle, struct inode *inode, sector_t iblock,
if (!create || err == -EIO)
goto cleanup;
- down(&ei->truncate_sem);
+ mutex_lock(&ei->truncate_mutex);
/*
* If the indirect block is missing while we are reading
@@ -723,7 +723,7 @@ ext3_get_block_handle(handle_t *handle, struct inode *inode, sector_t iblock,
}
partial = ext3_get_branch(inode, depth, offsets, chain, &err);
if (!partial) {
- up(&ei->truncate_sem);
+ mutex_unlock(&ei->truncate_mutex);
if (err)
goto cleanup;
clear_buffer_new(bh_result);
@@ -759,13 +759,13 @@ ext3_get_block_handle(handle_t *handle, struct inode *inode, sector_t iblock,
err = ext3_splice_branch(handle, inode, iblock, chain,
partial, left);
/*
- * i_disksize growing is protected by truncate_sem. Don't forget to
+ * i_disksize growing is protected by truncate_mutex. Don't forget to
* protect it if you're about to implement concurrent
* ext3_get_block() -bzzz
*/
if (!err && extend_disksize && inode->i_size > ei->i_disksize)
ei->i_disksize = inode->i_size;
- up(&ei->truncate_sem);
+ mutex_unlock(&ei->truncate_mutex);
if (err)
goto cleanup;
@@ -1227,7 +1227,7 @@ static int journal_dirty_data_fn(handle_t *handle, struct buffer_head *bh)
* ext3_file_write() -> generic_file_write() -> __alloc_pages() -> ...
*
* Same applies to ext3_get_block(). We will deadlock on various things like
- * lock_journal and i_truncate_sem.
+ * lock_journal and i_truncate_mutex.
*
* Setting PF_MEMALLOC here doesn't work - too many internal memory
* allocations fail.
@@ -2161,7 +2161,7 @@ void ext3_truncate(struct inode * inode)
* From here we block out all ext3_get_block() callers who want to
* modify the block allocation tree.
*/
- down(&ei->truncate_sem);
+ mutex_lock(&ei->truncate_mutex);
if (n == 1) { /* direct blocks */
ext3_free_data(handle, inode, NULL, i_data+offsets[0],
@@ -2228,7 +2228,7 @@ do_indirects:
ext3_discard_reservation(inode);
- up(&ei->truncate_sem);
+ mutex_unlock(&ei->truncate_mutex);
inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC;
ext3_mark_inode_dirty(handle, inode);
diff --git a/fs/ext3/ioctl.c b/fs/ext3/ioctl.c
index 556cd551007..aaf1da17b6d 100644
--- a/fs/ext3/ioctl.c
+++ b/fs/ext3/ioctl.c
@@ -182,7 +182,7 @@ flags_err:
* need to allocate reservation structure for this inode
* before set the window size
*/
- down(&ei->truncate_sem);
+ mutex_lock(&ei->truncate_mutex);
if (!ei->i_block_alloc_info)
ext3_init_block_alloc_info(inode);
@@ -190,7 +190,7 @@ flags_err:
struct ext3_reserve_window_node *rsv = &ei->i_block_alloc_info->rsv_window_node;
rsv->rsv_goal_size = rsv_window_size;
}
- up(&ei->truncate_sem);
+ mutex_unlock(&ei->truncate_mutex);
return 0;
}
case EXT3_IOC_GROUP_EXTEND: {
diff --git a/fs/ext3/super.c b/fs/ext3/super.c
index 56bf7658601..86e443182de 100644
--- a/fs/ext3/super.c
+++ b/fs/ext3/super.c
@@ -472,7 +472,7 @@ static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
#ifdef CONFIG_EXT3_FS_XATTR
init_rwsem(&ei->xattr_sem);
#endif
- init_MUTEX(&ei->truncate_sem);
+ mutex_init(&ei->truncate_mutex);
inode_init_once(&ei->vfs_inode);
}
}
@@ -481,7 +481,8 @@ static int init_inodecache(void)
{
ext3_inode_cachep = kmem_cache_create("ext3_inode_cache",
sizeof(struct ext3_inode_info),
- 0, SLAB_RECLAIM_ACCOUNT,
+ 0, (SLAB_RECLAIM_ACCOUNT|
+ SLAB_MEM_SPREAD),
init_once, NULL);
if (ext3_inode_cachep == NULL)
return -ENOMEM;
@@ -2325,7 +2326,8 @@ restore_opts:
static int ext3_statfs (struct super_block * sb, struct kstatfs * buf)
{
- struct ext3_super_block *es = EXT3_SB(sb)->s_es;
+ struct ext3_sb_info *sbi = EXT3_SB(sb);
+ struct ext3_super_block *es = sbi->s_es;
unsigned long overhead;
int i;
@@ -2367,12 +2369,12 @@ static int ext3_statfs (struct super_block * sb, struct kstatfs * buf)
buf->f_type = EXT3_SUPER_MAGIC;
buf->f_bsize = sb->s_blocksize;
buf->f_blocks = le32_to_cpu(es->s_blocks_count) - overhead;
- buf->f_bfree = ext3_count_free_blocks (sb);
+ buf->f_bfree = percpu_counter_sum(&sbi->s_freeblocks_counter);
buf->f_bavail = buf->f_bfree - le32_to_cpu(es->s_r_blocks_count);
if (buf->f_bfree < le32_to_cpu(es->s_r_blocks_count))
buf->f_bavail = 0;
buf->f_files = le32_to_cpu(es->s_inodes_count);
- buf->f_ffree = ext3_count_free_inodes (sb);
+ buf->f_ffree = percpu_counter_sum(&sbi->s_freeinodes_counter);
buf->f_namelen = EXT3_NAME_LEN;
return 0;
}
@@ -2382,8 +2384,8 @@ static int ext3_statfs (struct super_block * sb, struct kstatfs * buf)
* Process 1 Process 2
* ext3_create() quota_sync()
* journal_start() write_dquot()
- * DQUOT_INIT() down(dqio_sem)
- * down(dqio_sem) journal_start()
+ * DQUOT_INIT() down(dqio_mutex)
+ * down(dqio_mutex) journal_start()
*
*/