summaryrefslogtreecommitdiffstats
path: root/fs/ext2
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-06-19 22:45:37 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-06-19 22:45:37 +0000
commit6d403070f28cd44860fdb3a53be5da0275c65cf4 (patch)
tree0d0e7fe7b5fb7568d19e11d7d862b77a866ce081 /fs/ext2
parentecf1bf5f6c2e668d03b0a9fb026db7aa41e292e1 (diff)
Merge with 2.4.0-test1-ac21 + pile of MIPS cleanups to make merging
possible. Chainsawed RM200 kernel to compile again. Jazz machine status unknown.
Diffstat (limited to 'fs/ext2')
-rw-r--r--fs/ext2/balloc.c7
-rw-r--r--fs/ext2/dir.c2
-rw-r--r--fs/ext2/file.c3
-rw-r--r--fs/ext2/fsync.c133
-rw-r--r--fs/ext2/ialloc.c26
-rw-r--r--fs/ext2/inode.c44
-rw-r--r--fs/ext2/namei.c17
-rw-r--r--fs/ext2/super.c1
-rw-r--r--fs/ext2/truncate.c4
9 files changed, 61 insertions, 176 deletions
diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c
index a3f8ae4ce..97fb703e1 100644
--- a/fs/ext2/balloc.c
+++ b/fs/ext2/balloc.c
@@ -473,11 +473,8 @@ repeat:
if (i >= sb->u.ext2_sb.s_groups_count)
i = 0;
gdp = ext2_get_group_desc (sb, i, &bh2);
- if (!gdp) {
- *err = -EIO;
- unlock_super (sb);
- return 0;
- }
+ if (!gdp)
+ goto io_error;
if (le16_to_cpu(gdp->bg_free_blocks_count) > 0)
break;
}
diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c
index 3a18b375c..cd62f058d 100644
--- a/fs/ext2/dir.c
+++ b/fs/ext2/dir.c
@@ -26,7 +26,7 @@ struct file_operations ext2_dir_operations = {
read: generic_read_dir,
readdir: ext2_readdir,
ioctl: ext2_ioctl,
- fsync: ext2_sync_file,
+ fsync: ext2_fsync_file,
};
int ext2_check_dir_entry (const char * function, struct inode * dir,
diff --git a/fs/ext2/file.c b/fs/ext2/file.c
index d2c137e2c..130013e50 100644
--- a/fs/ext2/file.c
+++ b/fs/ext2/file.c
@@ -91,6 +91,7 @@ static int ext2_open_file (struct inode * inode, struct file * filp)
return 0;
}
+
/*
* We have mostly NULL's here: the current defaults are ok for
* the ext2 filesystem.
@@ -103,7 +104,7 @@ struct file_operations ext2_file_operations = {
mmap: generic_file_mmap,
open: ext2_open_file,
release: ext2_release_file,
- fsync: ext2_sync_file,
+ fsync: ext2_fsync_file,
};
struct inode_operations ext2_file_inode_operations = {
diff --git a/fs/ext2/fsync.c b/fs/ext2/fsync.c
index 52ffd6138..5b58f6cad 100644
--- a/fs/ext2/fsync.c
+++ b/fs/ext2/fsync.c
@@ -27,131 +27,28 @@
#include <linux/smp_lock.h>
-#define blocksize (EXT2_BLOCK_SIZE(inode->i_sb))
-#define addr_per_block (EXT2_ADDR_PER_BLOCK(inode->i_sb))
-
-static int sync_indirect(struct inode * inode, u32 * block, int wait)
-{
- struct buffer_head * bh;
-
- if (!*block)
- return 0;
- bh = get_hash_table(inode->i_dev, le32_to_cpu(*block), blocksize);
- if (!bh)
- return 0;
- if (wait && buffer_req(bh) && !buffer_uptodate(bh)) {
- /* There can be a parallell read(2) that started read-I/O
- on the buffer so we can't assume that there's been
- an I/O error without first waiting I/O completation. */
- wait_on_buffer(bh);
- if (!buffer_uptodate(bh))
- {
- brelse (bh);
- return -1;
- }
- }
- if (wait || !buffer_uptodate(bh) || !buffer_dirty(bh)) {
- if (wait)
- /* when we return from fsync all the blocks
- must be _just_ stored on disk */
- wait_on_buffer(bh);
- brelse(bh);
- return 0;
- }
- ll_rw_block(WRITE, 1, &bh);
- atomic_dec(&bh->b_count);
- return 0;
-}
-
-static int sync_iblock(struct inode * inode, u32 * iblock,
- struct buffer_head ** bh, int wait)
-{
- int rc, tmp;
-
- *bh = NULL;
- tmp = le32_to_cpu(*iblock);
- if (!tmp)
- return 0;
- rc = sync_indirect(inode, iblock, wait);
- if (rc)
- return rc;
- *bh = bread(inode->i_dev, tmp, blocksize);
- if (!*bh)
- return -1;
- return 0;
-}
-
-static int sync_dindirect(struct inode * inode, u32 * diblock, int wait)
-{
- int i;
- struct buffer_head * dind_bh;
- int rc, err = 0;
-
- rc = sync_iblock(inode, diblock, &dind_bh, wait);
- if (rc || !dind_bh)
- return rc;
-
- for (i = 0; i < addr_per_block; i++) {
- rc = sync_indirect(inode, ((u32 *) dind_bh->b_data) + i, wait);
- if (rc)
- err = rc;
- }
- brelse(dind_bh);
- return err;
-}
-
-static int sync_tindirect(struct inode * inode, u32 * tiblock, int wait)
-{
- int i;
- struct buffer_head * tind_bh;
- int rc, err = 0;
-
- rc = sync_iblock(inode, tiblock, &tind_bh, wait);
- if (rc || !tind_bh)
- return rc;
-
- for (i = 0; i < addr_per_block; i++) {
- rc = sync_dindirect(inode, ((u32 *) tind_bh->b_data) + i, wait);
- if (rc)
- err = rc;
- }
- brelse(tind_bh);
- return err;
-}
-
/*
* File may be NULL when we are called. Perhaps we shouldn't
* even pass file to fsync ?
*/
-int ext2_sync_file(struct file * file, struct dentry *dentry)
+int ext2_fsync_file(struct file * file, struct dentry *dentry, int datasync)
{
- int wait, err = 0;
struct inode *inode = dentry->d_inode;
+ return ext2_fsync_inode(inode, datasync);
+}
- lock_kernel();
- if (S_ISLNK(inode->i_mode) && !(inode->i_blocks))
- /*
- * Don't sync fast links!
- */
- goto skip;
-
- err = generic_buffer_fdatasync(inode, 0, ~0UL);
-
- for (wait=0; wait<=1; wait++)
- {
- err |= sync_indirect(inode,
- inode->u.ext2_i.i_data+EXT2_IND_BLOCK,
- wait);
- err |= sync_dindirect(inode,
- inode->u.ext2_i.i_data+EXT2_DIND_BLOCK,
- wait);
- err |= sync_tindirect(inode,
- inode->u.ext2_i.i_data+EXT2_TIND_BLOCK,
- wait);
- }
-skip:
- err |= ext2_sync_inode (inode);
- unlock_kernel();
+int ext2_fsync_inode(struct inode *inode, int datasync)
+{
+ int err;
+
+ err = fsync_inode_buffers(inode);
+ if (!(inode->i_state & I_DIRTY))
+ return err;
+ if (datasync && !(inode->i_state & I_DIRTY_DATASYNC))
+ return err;
+
+ err |= ext2_sync_inode(inode);
return err ? -EIO : 0;
}
+
diff --git a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c
index 277562ec7..cbc806cda 100644
--- a/fs/ext2/ialloc.c
+++ b/fs/ext2/ialloc.c
@@ -186,24 +186,6 @@ void ext2_free_inode (struct inode * inode)
struct ext2_group_desc * gdp;
struct ext2_super_block * es;
- if (!inode->i_dev) {
- printk ("ext2_free_inode: inode has no device\n");
- return;
- }
- if (inode->i_count > 1) {
- printk ("ext2_free_inode: inode has count=%d\n", inode->i_count);
- return;
- }
- if (inode->i_nlink) {
- printk ("ext2_free_inode: inode has nlink=%d\n",
- inode->i_nlink);
- return;
- }
- if (!sb) {
- printk("ext2_free_inode: inode on nonexistent device\n");
- return;
- }
-
ino = inode->i_ino;
ext2_debug ("freeing inode %lu\n", ino);
@@ -305,7 +287,6 @@ struct inode * ext2_new_inode (const struct inode * dir, int mode, int * err)
repeat:
gdp = NULL; i=0;
- *err = -ENOSPC;
if (S_ISDIR(mode)) {
avefreei = le32_to_cpu(es->s_free_inodes_count) /
sb->u.ext2_sb.s_groups_count;
@@ -387,6 +368,7 @@ repeat:
if (!gdp) {
unlock_super (sb);
iput(inode);
+ *err = -ENOSPC;
return NULL;
}
bitmap_nr = load_inode_bitmap (sb, i);
@@ -416,9 +398,8 @@ repeat:
ext2_error (sb, "ext2_new_inode",
"Free inodes count corrupted in group %d",
i);
- unlock_super (sb);
- iput (inode);
- return NULL;
+ /* If we continue recover from this case */
+ gdp->bg_free_inodes_count = 0;
}
goto repeat;
}
@@ -429,6 +410,7 @@ repeat:
"block_group = %d,inode=%d", i, j);
unlock_super (sb);
iput (inode);
+ *err = EIO; /* Should never happen */
return NULL;
}
gdp->bg_free_inodes_count =
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
index 7e5263fb1..d3abb7cb2 100644
--- a/fs/ext2/inode.c
+++ b/fs/ext2/inode.c
@@ -117,7 +117,7 @@ static int ext2_alloc_block (struct inode * inode, unsigned long goal, int *err)
inode->u.ext2_i.i_prealloc_count--;
ext2_debug ("preallocation hit (%lu/%lu).\n",
++alloc_hits, ++alloc_attempts);
-
+ *err = 0;
} else {
ext2_discard_prealloc (inode);
ext2_debug ("preallocation miss (%lu/%lu).\n",
@@ -200,6 +200,7 @@ out:
return ret;
}
+/* returns NULL and sets *err on error */
static struct buffer_head * inode_getblk (struct inode * inode, int nr,
int new_block, int * err, int metadata, long *phys, int *new)
{
@@ -223,7 +224,6 @@ repeat:
return NULL;
}
}
- *err = -EFBIG;
/* Check file limits.. */
{
@@ -311,7 +311,7 @@ repeat:
* can fail due to: - not present
* - out of space
*
- * NULL return in the data case is mandatory.
+ * NULL return in the data case, or an error, is mandatory.
*/
static struct buffer_head * block_getblk (struct inode * inode,
struct buffer_head * bh, int nr,
@@ -341,6 +341,7 @@ repeat:
if (tmp == le32_to_cpu(*p))
goto out;
brelse (result);
+ result = NULL;
goto repeat;
} else {
*phys = tmp;
@@ -402,11 +403,9 @@ repeat:
*new = 1;
}
*p = le32_to_cpu(tmp);
- mark_buffer_dirty(bh, 1);
- if (IS_SYNC(inode) || inode->u.ext2_i.i_osync) {
+ mark_buffer_dirty_inode(bh, 1, inode);
+ if (IS_SYNC(inode) || inode->u.ext2_i.i_osync)
ll_rw_block (WRITE, 1, &bh);
- wait_on_buffer (bh);
- }
inode->i_ctime = CURRENT_TIME;
inode->i_blocks += blocksize/512;
mark_inode_dirty(inode);
@@ -487,9 +486,9 @@ static int ext2_get_block(struct inode *inode, long iblock, struct buffer_head *
#define GET_INODE_PTR(x) \
inode_getblk(inode, x, iblock, &err, 1, NULL, NULL)
#define GET_INDIRECT_DATABLOCK(x) \
- block_getblk (inode, bh, x, iblock, &err, 0, &phys, &new);
+ block_getblk (inode, bh, x, iblock, &err, 0, &phys, &new)
#define GET_INDIRECT_PTR(x) \
- block_getblk (inode, bh, x, iblock, &err, 1, NULL, NULL);
+ block_getblk (inode, bh, x, iblock, &err, 1, NULL, NULL)
if (ptr < direct_blocks) {
bh = GET_INODE_DATABLOCK(ptr);
@@ -547,13 +546,11 @@ abort_too_big:
struct buffer_head * ext2_getblk(struct inode * inode, long block, int create, int * err)
{
struct buffer_head dummy;
- int error;
dummy.b_state = 0;
dummy.b_blocknr = -1000;
- error = ext2_get_block(inode, block, &dummy, create);
- *err = error;
- if (!error && buffer_mapped(&dummy)) {
+ *err = ext2_get_block(inode, block, &dummy, create);
+ if (!*err && buffer_mapped(&dummy)) {
struct buffer_head *bh;
bh = getblk(dummy.b_dev, dummy.b_blocknr, inode->i_sb->s_blocksize);
if (buffer_new(&dummy)) {
@@ -881,8 +878,23 @@ static int ext2_update_inode(struct inode * inode, int do_sync)
raw_inode->i_file_acl = cpu_to_le32(inode->u.ext2_i.i_file_acl);
if (S_ISDIR(inode->i_mode))
raw_inode->i_dir_acl = cpu_to_le32(inode->u.ext2_i.i_dir_acl);
- else
+ else {
raw_inode->i_size_high = cpu_to_le32(inode->i_size >> 32);
+ if (inode->i_size >> 31) {
+ struct super_block *sb = inode->i_sb;
+ struct ext2_super_block *es = sb->u.ext2_sb.s_es;
+ if (!(es->s_feature_ro_compat & cpu_to_le32(EXT2_FEATURE_RO_COMPAT_LARGE_FILE))) {
+ /* If this is the first large file
+ * created, add a flag to the superblock
+ * SMP Note: we're currently protected by the
+ * big kernel lock here, so this will need
+ * to be changed if that's no longer true.
+ */
+ es->s_feature_ro_compat |= cpu_to_le32(EXT2_FEATURE_RO_COMPAT_LARGE_FILE);
+ ext2_write_super(sb);
+ }
+ }
+ }
raw_inode->i_generation = cpu_to_le32(inode->i_generation);
if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
@@ -904,10 +916,10 @@ static int ext2_update_inode(struct inode * inode, int do_sync)
return err;
}
-void ext2_write_inode (struct inode * inode)
+void ext2_write_inode (struct inode * inode, int wait)
{
lock_kernel();
- ext2_update_inode (inode, 0);
+ ext2_update_inode (inode, wait);
unlock_kernel();
}
diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c
index 3e471f42b..116b4852f 100644
--- a/fs/ext2/namei.c
+++ b/fs/ext2/namei.c
@@ -366,12 +366,9 @@ static int ext2_create (struct inode * dir, struct dentry * dentry, int mode)
struct inode * inode;
int err;
- /*
- * N.B. Several error exits in ext2_new_inode don't set err.
- */
inode = ext2_new_inode (dir, mode, &err);
if (!inode)
- return -EIO;
+ return err;
inode->i_op = &ext2_file_inode_operations;
inode->i_fop = &ext2_file_operations;
@@ -397,7 +394,7 @@ static int ext2_mknod (struct inode * dir, struct dentry *dentry, int mode, int
inode = ext2_new_inode (dir, mode, &err);
if (!inode)
- return -EIO;
+ return err;
inode->i_uid = current->fsuid;
init_special_inode(inode, mode, rdev);
@@ -428,7 +425,7 @@ static int ext2_mkdir(struct inode * dir, struct dentry * dentry, int mode)
inode = ext2_new_inode (dir, S_IFDIR, &err);
if (!inode)
- return -EIO;
+ return err;
inode->i_op = &ext2_dir_inode_operations;
inode->i_fop = &ext2_dir_operations;
@@ -454,7 +451,7 @@ static int ext2_mkdir(struct inode * dir, struct dentry * dentry, int mode)
strcpy (de->name, "..");
ext2_set_de_type(dir->i_sb, de, S_IFDIR);
inode->i_nlink = 2;
- mark_buffer_dirty(dir_block, 1);
+ mark_buffer_dirty_inode(dir_block, 1, dir);
brelse (dir_block);
inode->i_mode = S_IFDIR | mode;
if (dir->i_mode & S_ISGID)
@@ -634,7 +631,7 @@ static int ext2_symlink (struct inode * dir, struct dentry *dentry, const char *
return -ENAMETOOLONG;
if (!(inode = ext2_new_inode (dir, S_IFLNK, &err)))
- return -EIO;
+ return err;
inode->i_mode = S_IFLNK | S_IRWXUGO;
@@ -685,7 +682,7 @@ static int ext2_link (struct dentry * old_dentry,
inode->i_nlink++;
inode->i_ctime = CURRENT_TIME;
mark_inode_dirty(inode);
- inode->i_count++;
+ atomic_inc(&inode->i_count);
d_instantiate(dentry, inode);
return 0;
}
@@ -791,7 +788,7 @@ static int ext2_rename (struct inode * old_dir, struct dentry *old_dentry,
mark_inode_dirty(old_dir);
if (dir_bh) {
PARENT_INO(dir_bh->b_data) = le32_to_cpu(new_dir->i_ino);
- mark_buffer_dirty(dir_bh, 1);
+ mark_buffer_dirty_inode(dir_bh, 1, old_inode);
old_dir->i_nlink--;
mark_inode_dirty(old_dir);
if (new_inode) {
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index aa6a599fc..d3af3b992 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -593,7 +593,6 @@ struct super_block * ext2_read_super (struct super_block * sb, void * data,
/*
* set up enough so that it can read an inode
*/
- sb->s_dev = dev;
sb->s_op = &ext2_sops;
sb->s_root = d_alloc_root(iget(sb, EXT2_ROOT_INO));
if (!sb->s_root) {
diff --git a/fs/ext2/truncate.c b/fs/ext2/truncate.c
index ba8397196..1c05cc09f 100644
--- a/fs/ext2/truncate.c
+++ b/fs/ext2/truncate.c
@@ -211,7 +211,7 @@ static int trunc_indirect (struct inode * inode, int offset, u32 * p, struct buf
inode->i_ino, tmp);
*p = 0;
if (dind_bh)
- mark_buffer_dirty(dind_bh, 1);
+ mark_buffer_dirty_inode(dind_bh, 1, inode);
else
mark_inode_dirty(inode);
return 0;
@@ -279,7 +279,7 @@ static int trunc_dindirect (struct inode * inode, int offset, u32 * p,
inode->i_ino, tmp);
*p = 0;
if (tind_bh)
- mark_buffer_dirty(tind_bh, 1);
+ mark_buffer_dirty_inode(tind_bh, 1, inode);
else
mark_inode_dirty(inode);
return 0;