summaryrefslogtreecommitdiffstats
path: root/fs/ext2
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-08-08 12:37:17 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-08-08 12:37:17 +0000
commit9aa9eb41942b918f385ccabd2efdd6e7e4232165 (patch)
tree20bec7da036d31ec185dfc1dcc00753c7ac9b170 /fs/ext2
parent87075e049581f880f01eb0b41aa6ac807b299e35 (diff)
Merge with Linux 2.4.0-test6-pre1.
Diffstat (limited to 'fs/ext2')
-rw-r--r--fs/ext2/balloc.c57
-rw-r--r--fs/ext2/file.c6
-rw-r--r--fs/ext2/inode.c342
-rw-r--r--fs/ext2/super.c89
4 files changed, 294 insertions, 200 deletions
diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c
index a3f8ae4ce..8ca28e0a0 100644
--- a/fs/ext2/balloc.c
+++ b/fs/ext2/balloc.c
@@ -16,7 +16,6 @@
#include <linux/locks.h>
#include <linux/quotaops.h>
-
/*
* balloc.c contains the blocks allocation and deallocation routines
*/
@@ -379,10 +378,8 @@ int ext2_new_block (const struct inode * inode, unsigned long goal,
((sb->u.ext2_sb.s_resuid != current->fsuid) &&
(sb->u.ext2_sb.s_resgid == 0 ||
!in_group_p (sb->u.ext2_sb.s_resgid)) &&
- !capable(CAP_SYS_RESOURCE))) {
- unlock_super (sb);
- return 0;
- }
+ !capable(CAP_SYS_RESOURCE)))
+ goto out;
ext2_debug ("goal=%lu.\n", goal);
@@ -475,16 +472,13 @@ repeat:
gdp = ext2_get_group_desc (sb, i, &bh2);
if (!gdp) {
*err = -EIO;
- unlock_super (sb);
- return 0;
+ goto out;
}
if (le16_to_cpu(gdp->bg_free_blocks_count) > 0)
break;
}
- if (k >= sb->u.ext2_sb.s_groups_count) {
- unlock_super (sb);
- return 0;
- }
+ if (k >= sb->u.ext2_sb.s_groups_count)
+ goto out;
bitmap_nr = load_block_bitmap (sb, i);
if (bitmap_nr < 0)
goto io_error;
@@ -500,8 +494,7 @@ repeat:
if (j >= EXT2_BLOCKS_PER_GROUP(sb)) {
ext2_error (sb, "ext2_new_block",
"Free blocks count corrupted for block group %d", i);
- unlock_super (sb);
- return 0;
+ goto out;
}
search_back:
@@ -520,9 +513,8 @@ got_block:
* Check quota for allocation of this block.
*/
if(DQUOT_ALLOC_BLOCK(sb, inode, 1)) {
- unlock_super(sb);
*err = -EDQUOT;
- return 0;
+ goto out;
}
tmp = j + i * EXT2_BLOCKS_PER_GROUP(sb) + le32_to_cpu(es->s_first_data_block);
@@ -550,31 +542,50 @@ got_block:
#ifdef EXT2_PREALLOCATE
if (prealloc_block) {
int prealloc_goal;
+ unsigned long next_block = tmp + 1;
prealloc_goal = es->s_prealloc_blocks ?
es->s_prealloc_blocks : EXT2_DEFAULT_PREALLOC_BLOCKS;
+ /* Writer: ->i_prealloc* */
+ /*
+ * Can't happen right now, will need handling if we go for
+ * per-group spinlocks. Handling == skipping preallocation if
+ * condition below will be true. For now there is no legitimate
+ * way it could happen, thus the BUG().
+ */
+ if (*prealloc_count)
+ BUG();
*prealloc_count = 0;
- *prealloc_block = tmp + 1;
+ *prealloc_block = next_block;
+ /* Writer: end */
for (k = 1;
k < prealloc_goal && (j + k) < EXT2_BLOCKS_PER_GROUP(sb);
- k++) {
+ k++, next_block++) {
if (DQUOT_PREALLOC_BLOCK(sb, inode, 1))
break;
- if (ext2_set_bit (j + k, bh->b_data)) {
+ /* Writer: ->i_prealloc* */
+ if (*prealloc_block + *prealloc_count != next_block ||
+ ext2_set_bit (j + k, bh->b_data)) {
+ /* Writer: end */
DQUOT_FREE_BLOCK(sb, inode, 1);
break;
}
(*prealloc_count)++;
+ /* Writer: end */
}
+ /*
+ * As soon as we go for per-group spinlocks we'll need these
+ * done inside the loop above.
+ */
gdp->bg_free_blocks_count =
cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count) -
- *prealloc_count);
+ (k - 1));
es->s_free_blocks_count =
cpu_to_le32(le32_to_cpu(es->s_free_blocks_count) -
- *prealloc_count);
+ (k - 1));
ext2_debug ("Preallocated a further %lu bits.\n",
- *prealloc_count);
+ (k - 1));
}
#endif
@@ -591,8 +602,7 @@ got_block:
"block(%d) >= blocks count(%d) - "
"block_group = %d, es == %p ",j,
le32_to_cpu(es->s_blocks_count), i, es);
- unlock_super (sb);
- return 0;
+ goto out;
}
ext2_debug ("allocating block %d. "
@@ -609,6 +619,7 @@ got_block:
io_error:
*err = -EIO;
+out:
unlock_super (sb);
return 0;
diff --git a/fs/ext2/file.c b/fs/ext2/file.c
index 1b9983e24..27b1fcbcb 100644
--- a/fs/ext2/file.c
+++ b/fs/ext2/file.c
@@ -20,7 +20,6 @@
#include <linux/fs.h>
#include <linux/sched.h>
-#include <linux/smp_lock.h>
static loff_t ext2_file_lseek(struct file *, loff_t, int);
static int ext2_open_file (struct inode *, struct file *);
@@ -74,11 +73,8 @@ static loff_t ext2_file_lseek(
*/
static int ext2_release_file (struct inode * inode, struct file * filp)
{
- if (filp->f_mode & FMODE_WRITE) {
- lock_kernel();
+ if (filp->f_mode & FMODE_WRITE)
ext2_discard_prealloc (inode);
- unlock_kernel();
- }
return 0;
}
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
index 4580c87e0..c7234e7b5 100644
--- a/fs/ext2/inode.c
+++ b/fs/ext2/inode.c
@@ -35,9 +35,7 @@ static int ext2_update_inode(struct inode * inode, int do_sync);
*/
void ext2_put_inode (struct inode * inode)
{
- lock_kernel();
ext2_discard_prealloc (inode);
- unlock_kernel();
}
/*
@@ -66,19 +64,6 @@ no_delete:
clear_inode(inode); /* We must guarantee clearing of inode... */
}
-#define inode_bmap(inode, nr) (le32_to_cpu((inode)->u.ext2_i.i_data[(nr)]))
-
-static inline int block_bmap (struct buffer_head * bh, int nr)
-{
- int tmp;
-
- if (!bh)
- return 0;
- tmp = le32_to_cpu(((u32 *) bh->b_data)[nr]);
- brelse (bh);
- return tmp;
-}
-
/*
* ext2_discard_prealloc and ext2_alloc_block are atomic wrt. the
* superblock in the same manner as are ext2_free_blocks and
@@ -91,11 +76,13 @@ void ext2_discard_prealloc (struct inode * inode)
#ifdef EXT2_PREALLOCATE
unsigned short total;
+ lock_kernel();
if (inode->u.ext2_i.i_prealloc_count) {
total = inode->u.ext2_i.i_prealloc_count;
inode->u.ext2_i.i_prealloc_count = 0;
ext2_free_blocks (inode, inode->u.ext2_i.i_prealloc_block, total);
}
+ unlock_kernel();
#endif
}
@@ -135,69 +122,181 @@ static int ext2_alloc_block (struct inode * inode, unsigned long goal, int *err)
return result;
}
-static inline long ext2_block_map (struct inode * inode, long block)
+typedef struct {
+ u32 *p;
+ u32 key;
+ struct buffer_head *bh;
+} Indirect;
+
+static inline void add_chain(Indirect *p, struct buffer_head *bh, u32 *v)
+{
+ p->key = *(p->p = v);
+ p->bh = bh;
+}
+
+static inline int verify_chain(Indirect *from, Indirect *to)
+{
+ while (from <= to && from->key == *from->p)
+ from++;
+ return (from > to);
+}
+
+/**
+ * ext2_block_to_path - parse the block number into array of offsets
+ * @inode: inode in question (we are only interested in its superblock)
+ * @i_block: block number to be parsed
+ * @offsets: array to store the offsets in
+ *
+ * To store the locations of file's data ext2 uses a data structure common
+ * for UNIX filesystems - tree of pointers anchored in the inode, with
+ * data blocks at leaves and indirect blocks in intermediate nodes.
+ * This function translates the block number into path in that tree -
+ * return value is the path length and @offsets[n] is the offset of
+ * pointer to (n+1)th node in the nth one. If @block is out of range
+ * (negative or too large) warning is printed and zero returned.
+ *
+ * Note: function doesn't find node addresses, so no IO is needed. All
+ * we need to know is the capacity of indirect blocks (taken from the
+ * inode->i_sb).
+ */
+
+/*
+ * Portability note: the last comparison (check that we fit into triple
+ * indirect block) is spelled differently, because otherwise on an
+ * architecture with 32-bit longs and 8Kb pages we might get into trouble
+ * if our filesystem had 8Kb blocks. We might use long long, but that would
+ * kill us on x86. Oh, well, at least the sign propagation does not matter -
+ * i_block would have to be negative in the very beginning, so we would not
+ * get there at all.
+ */
+
+static int ext2_block_to_path(struct inode *inode, long i_block, int offsets[4])
{
- int i, ret;
int ptrs = EXT2_ADDR_PER_BLOCK(inode->i_sb);
int ptrs_bits = EXT2_ADDR_PER_BLOCK_BITS(inode->i_sb);
-
- ret = 0;
- lock_kernel();
- if (block < 0) {
- ext2_warning (inode->i_sb, "ext2_block_map", "block < 0");
- goto out;
- }
- if (block >= EXT2_NDIR_BLOCKS + ptrs +
- (1 << (ptrs_bits * 2)) +
- ((1 << (ptrs_bits * 2)) << ptrs_bits)) {
- ext2_warning (inode->i_sb, "ext2_block_map", "block > big");
- goto out;
- }
- if (block < EXT2_NDIR_BLOCKS) {
- ret = inode_bmap (inode, block);
- goto out;
- }
- block -= EXT2_NDIR_BLOCKS;
- if (block < ptrs) {
- i = inode_bmap (inode, EXT2_IND_BLOCK);
- if (!i)
- goto out;
- ret = block_bmap (bread (inode->i_dev, i,
- inode->i_sb->s_blocksize), block);
- goto out;
+ const long direct_blocks = EXT2_NDIR_BLOCKS,
+ indirect_blocks = ptrs,
+ double_blocks = (1 << (ptrs_bits * 2));
+ int n = 0;
+
+ if (i_block < 0) {
+ ext2_warning (inode->i_sb, "ext2_block_to_path", "block < 0");
+ } else if (i_block < direct_blocks) {
+ offsets[n++] = i_block;
+ } else if ( (i_block -= direct_blocks) < indirect_blocks) {
+ offsets[n++] = EXT2_IND_BLOCK;
+ offsets[n++] = i_block;
+ } else if ((i_block -= indirect_blocks) < double_blocks) {
+ offsets[n++] = EXT2_DIND_BLOCK;
+ offsets[n++] = i_block >> ptrs_bits;
+ offsets[n++] = i_block & (ptrs - 1);
+ } else if (((i_block -= double_blocks) >> (ptrs_bits * 2)) < ptrs) {
+ offsets[n++] = EXT2_TIND_BLOCK;
+ offsets[n++] = i_block >> (ptrs_bits * 2);
+ offsets[n++] = (i_block >> ptrs_bits) & (ptrs - 1);
+ offsets[n++] = i_block & (ptrs - 1);
+ } else {
+ ext2_warning (inode->i_sb, "ext2_block_to_path", "block > big");
}
- block -= ptrs;
- if (block < (1 << (ptrs_bits * 2))) {
- i = inode_bmap (inode, EXT2_DIND_BLOCK);
- if (!i)
- goto out;
- i = block_bmap (bread (inode->i_dev, i,
- inode->i_sb->s_blocksize),
- block >> ptrs_bits);
- if (!i)
- goto out;
- ret = block_bmap (bread (inode->i_dev, i,
- inode->i_sb->s_blocksize),
- block & (ptrs - 1));
- goto out;
+ return n;
+}
+
+/**
+ * ext2_get_branch - read the chain of indirect blocks leading to data
+ * @inode: inode in question
+ * @depth: depth of the chain (1 - direct pointer, etc.)
+ * @offsets: offsets of pointers in inode/indirect blocks
+ * @chain: place to store the result
+ * @err: here we store the error value
+ *
+ * Function fills the array of triples <key, p, bh> and returns %NULL
+ * if everything went OK or the pointer to the last filled triple
+ * (incomplete one) otherwise. Upon the return chain[i].key contains
+ * the number of (i+1)-th block in the chain (as it is stored in memory,
+ * i.e. little-endian 32-bit), chain[i].p contains the address of that
+ * number (it points into struct inode for i==0 and into the bh->b_data
+ * for i>0) and chain[i].bh points to the buffer_head of i-th indirect
+ * block for i>0 and NULL for i==0. In other words, it holds the block
+ * numbers of the chain, addresses they were taken from (and where we can
+ * verify that chain did not change) and buffer_heads hosting these
+ * numbers.
+ *
+ * Function stops when it stumbles upon zero pointer (absent block)
+ * (pointer to last triple returned, *@err == 0)
+ * or when it gets an IO error reading an indirect block
+ * (ditto, *@err == -EIO)
+ * or when it notices that chain had been changed while it was reading
+ * (ditto, *@err == -EAGAIN)
+ * or when it reads all @depth-1 indirect blocks successfully and finds
+ * the whole chain, all way to the data (returns %NULL, *err == 0).
+ */
+static inline Indirect *ext2_get_branch(struct inode *inode,
+ int depth,
+ int *offsets,
+ Indirect chain[4],
+ int *err)
+{
+ kdev_t dev = inode->i_dev;
+ int size = inode->i_sb->s_blocksize;
+ Indirect *p = chain;
+ struct buffer_head *bh;
+
+ *err = 0;
+ /* i_data is not going away, no lock needed */
+ add_chain (chain, NULL, inode->u.ext2_i.i_data + *offsets);
+ if (!p->key)
+ goto no_block;
+ /*
+ * switch below is merely an unrolled loop - body should be
+ * repeated depth-1 times. Maybe loop would be actually better,
+ * but that way we get straight execution path in normal cases.
+ * Easy to change, anyway - all cases in switch are literally
+ * identical.
+ */
+ switch (depth) {
+ case 4:
+ bh = bread(dev, le32_to_cpu(p->key), size);
+ if (!bh)
+ goto failure;
+ /* Reader: pointers */
+ if (!verify_chain(chain, p))
+ goto changed;
+ add_chain(++p, bh, (u32*)bh->b_data + *++offsets);
+ /* Reader: end */
+ if (!p->key)
+ goto no_block;
+ case 3:
+ bh = bread(dev, le32_to_cpu(p->key), size);
+ if (!bh)
+ goto failure;
+ /* Reader: pointers */
+ if (!verify_chain(chain, p))
+ goto changed;
+ add_chain(++p, bh, (u32*)bh->b_data + *++offsets);
+ /* Reader: end */
+ if (!p->key)
+ goto no_block;
+ case 2:
+ bh = bread(dev, le32_to_cpu(p->key), size);
+ if (!bh)
+ goto failure;
+ /* Reader: pointers */
+ if (!verify_chain(chain, p))
+ goto changed;
+ add_chain(++p, bh, (u32*)bh->b_data + *++offsets);
+ /* Reader: end */
+ if (!p->key)
+ goto no_block;
}
- block -= (1 << (ptrs_bits * 2));
- i = inode_bmap (inode, EXT2_TIND_BLOCK);
- if (!i)
- goto out;
- i = block_bmap (bread (inode->i_dev, i, inode->i_sb->s_blocksize),
- block >> (ptrs_bits * 2));
- if (!i)
- goto out;
- i = block_bmap (bread (inode->i_dev, i, inode->i_sb->s_blocksize),
- (block >> ptrs_bits) & (ptrs - 1));
- if (!i)
- goto out;
- ret = block_bmap (bread (inode->i_dev, i, inode->i_sb->s_blocksize),
- block & (ptrs - 1));
-out:
- unlock_kernel();
- return ret;
+ return NULL;
+
+changed:
+ *err = -EAGAIN;
+ goto no_block;
+failure:
+ *err = -EIO;
+no_block:
+ return p;
}
static struct buffer_head * inode_getblk (struct inode * inode, int nr,
@@ -396,28 +495,37 @@ static int ext2_get_block(struct inode *inode, long iblock, struct buffer_head *
{
int ret, err, new;
struct buffer_head *bh;
- unsigned long ptr, phys;
- /*
- * block pointers per block
- */
- unsigned long ptrs = EXT2_ADDR_PER_BLOCK(inode->i_sb);
- int ptrs_bits = EXT2_ADDR_PER_BLOCK_BITS(inode->i_sb);
- const int direct_blocks = EXT2_NDIR_BLOCKS,
- indirect_blocks = ptrs,
- double_blocks = (1 << (ptrs_bits * 2)),
- triple_blocks = (1 << (ptrs_bits * 3));
+ unsigned long phys;
+ int offsets[4];
+ int *p;
+ Indirect chain[4];
+ Indirect *partial;
+ int depth;
+
+ depth = ext2_block_to_path(inode, iblock, offsets);
+ if (depth == 0)
+ goto abort;
+
+ lock_kernel();
+ partial = ext2_get_branch(inode, depth, offsets, chain, &err);
+
+ if (!partial) {
+ unlock_kernel();
+ for (partial = chain + depth - 1; partial > chain; partial--)
+ brelse(partial->bh);
+ bh_result->b_dev = inode->i_dev;
+ bh_result->b_blocknr = le32_to_cpu(chain[depth-1].key);
+ bh_result->b_state |= (1UL << BH_Mapped);
+ return 0;
+ }
+
+ while (partial > chain) {
+ brelse(partial->bh);
+ partial--;
+ }
if (!create) {
- /*
- * Will clean this up further, ext2_block_map() should use the
- * bh instead of an integer block-number interface.
- */
- phys = ext2_block_map(inode, iblock);
- if (phys) {
- bh_result->b_dev = inode->i_dev;
- bh_result->b_blocknr = phys;
- bh_result->b_state |= (1UL << BH_Mapped);
- }
+ unlock_kernel();
return 0;
}
@@ -426,14 +534,6 @@ static int ext2_get_block(struct inode *inode, long iblock, struct buffer_head *
ret = 0;
bh = NULL;
- lock_kernel();
-
- if (iblock < 0)
- goto abort_negative;
- if (iblock > direct_blocks + indirect_blocks +
- double_blocks + triple_blocks)
- goto abort_too_big;
-
/*
* If this is a sequential block allocation, set the next_alloc_block
* to this block now so that all the indblock and data block
@@ -450,7 +550,6 @@ static int ext2_get_block(struct inode *inode, long iblock, struct buffer_head *
}
err = 0;
- ptr = iblock;
/*
* ok, these macros clean the logic up a bit and make
@@ -465,27 +564,20 @@ static int ext2_get_block(struct inode *inode, long iblock, struct buffer_head *
#define GET_INDIRECT_PTR(x) \
block_getblk (inode, bh, x, iblock, &err, 1, NULL, NULL);
- if (ptr < direct_blocks) {
- bh = GET_INODE_DATABLOCK(ptr);
+ p = offsets;
+ if (depth == 1) {
+ bh = GET_INODE_DATABLOCK(*p);
goto out;
}
- ptr -= direct_blocks;
- if (ptr < indirect_blocks) {
- bh = GET_INODE_PTR(EXT2_IND_BLOCK);
- goto get_indirect;
+ bh = GET_INODE_PTR(*p);
+ switch (depth) {
+ default: /* case 4: */
+ bh = GET_INDIRECT_PTR(*++p);
+ case 3:
+ bh = GET_INDIRECT_PTR(*++p);
+ case 2:
+ bh = GET_INDIRECT_DATABLOCK(*++p);
}
- ptr -= indirect_blocks;
- if (ptr < double_blocks) {
- bh = GET_INODE_PTR(EXT2_DIND_BLOCK);
- goto get_double;
- }
- ptr -= double_blocks;
- bh = GET_INODE_PTR(EXT2_TIND_BLOCK);
- bh = GET_INDIRECT_PTR(ptr >> (ptrs_bits * 2));
-get_double:
- bh = GET_INDIRECT_PTR((ptr >> ptrs_bits) & (ptrs - 1));
-get_indirect:
- bh = GET_INDIRECT_DATABLOCK(ptr & (ptrs - 1));
#undef GET_INODE_DATABLOCK
#undef GET_INODE_PTR
@@ -505,17 +597,9 @@ out:
bh_result->b_state |= (1UL << BH_Mapped); /* safe */
if (new)
bh_result->b_state |= (1UL << BH_New);
-abort:
unlock_kernel();
+abort:
return err;
-
-abort_negative:
- ext2_warning (inode->i_sb, "ext2_get_block", "block < 0");
- goto abort;
-
-abort_too_big:
- ext2_warning (inode->i_sb, "ext2_get_block", "block > big");
- goto abort;
}
struct buffer_head * ext2_getblk(struct inode * inode, long block, int create, int * err)
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index e395c75a1..bca514ee5 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -254,53 +254,56 @@ static int parse_options (char * options, unsigned long * sb_block,
return 1;
}
-static void ext2_setup_super (struct super_block * sb,
- struct ext2_super_block * es)
+static int ext2_setup_super (struct super_block * sb,
+ struct ext2_super_block * es,
+ int read_only)
{
+ int res = 0;
if (le32_to_cpu(es->s_rev_level) > EXT2_MAX_SUPP_REV) {
printk ("EXT2-fs warning: revision level too high, "
"forcing read/only mode\n");
- sb->s_flags |= MS_RDONLY;
+ res = MS_RDONLY;
}
- if (!(sb->s_flags & MS_RDONLY)) {
- if (!(sb->u.ext2_sb.s_mount_state & EXT2_VALID_FS))
- printk ("EXT2-fs warning: mounting unchecked fs, "
- "running e2fsck is recommended\n");
- else if ((sb->u.ext2_sb.s_mount_state & EXT2_ERROR_FS))
- printk ("EXT2-fs warning: mounting fs with errors, "
- "running e2fsck is recommended\n");
- else if ((__s16) le16_to_cpu(es->s_max_mnt_count) >= 0 &&
- le16_to_cpu(es->s_mnt_count) >=
- (unsigned short) (__s16) le16_to_cpu(es->s_max_mnt_count))
- printk ("EXT2-fs warning: maximal mount count reached, "
- "running e2fsck is recommended\n");
- else if (le32_to_cpu(es->s_checkinterval) &&
- (le32_to_cpu(es->s_lastcheck) + le32_to_cpu(es->s_checkinterval) <= CURRENT_TIME))
- printk ("EXT2-fs warning: checktime reached, "
- "running e2fsck is recommended\n");
- es->s_state = cpu_to_le16(le16_to_cpu(es->s_state) & ~EXT2_VALID_FS);
- if (!(__s16) le16_to_cpu(es->s_max_mnt_count))
- es->s_max_mnt_count = (__s16) cpu_to_le16(EXT2_DFL_MAX_MNT_COUNT);
- es->s_mnt_count=cpu_to_le16(le16_to_cpu(es->s_mnt_count) + 1);
- es->s_mtime = cpu_to_le32(CURRENT_TIME);
- mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1);
- sb->s_dirt = 1;
- if (test_opt (sb, DEBUG))
- printk ("[EXT II FS %s, %s, bs=%lu, fs=%lu, gc=%lu, "
- "bpg=%lu, ipg=%lu, mo=%04lx]\n",
- EXT2FS_VERSION, EXT2FS_DATE, sb->s_blocksize,
- sb->u.ext2_sb.s_frag_size,
- sb->u.ext2_sb.s_groups_count,
- EXT2_BLOCKS_PER_GROUP(sb),
- EXT2_INODES_PER_GROUP(sb),
- sb->u.ext2_sb.s_mount_opt);
+ if (read_only)
+ return res;
+ if (!(sb->u.ext2_sb.s_mount_state & EXT2_VALID_FS))
+ printk ("EXT2-fs warning: mounting unchecked fs, "
+ "running e2fsck is recommended\n");
+ else if ((sb->u.ext2_sb.s_mount_state & EXT2_ERROR_FS))
+ printk ("EXT2-fs warning: mounting fs with errors, "
+ "running e2fsck is recommended\n");
+ else if ((__s16) le16_to_cpu(es->s_max_mnt_count) >= 0 &&
+ le16_to_cpu(es->s_mnt_count) >=
+ (unsigned short) (__s16) le16_to_cpu(es->s_max_mnt_count))
+ printk ("EXT2-fs warning: maximal mount count reached, "
+ "running e2fsck is recommended\n");
+ else if (le32_to_cpu(es->s_checkinterval) &&
+ (le32_to_cpu(es->s_lastcheck) + le32_to_cpu(es->s_checkinterval) <= CURRENT_TIME))
+ printk ("EXT2-fs warning: checktime reached, "
+ "running e2fsck is recommended\n");
+ es->s_state = cpu_to_le16(le16_to_cpu(es->s_state) & ~EXT2_VALID_FS);
+ if (!(__s16) le16_to_cpu(es->s_max_mnt_count))
+ es->s_max_mnt_count = (__s16) cpu_to_le16(EXT2_DFL_MAX_MNT_COUNT);
+ es->s_mnt_count=cpu_to_le16(le16_to_cpu(es->s_mnt_count) + 1);
+ es->s_mtime = cpu_to_le32(CURRENT_TIME);
+ mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1);
+ sb->s_dirt = 1;
+ if (test_opt (sb, DEBUG))
+ printk ("[EXT II FS %s, %s, bs=%lu, fs=%lu, gc=%lu, "
+ "bpg=%lu, ipg=%lu, mo=%04lx]\n",
+ EXT2FS_VERSION, EXT2FS_DATE, sb->s_blocksize,
+ sb->u.ext2_sb.s_frag_size,
+ sb->u.ext2_sb.s_groups_count,
+ EXT2_BLOCKS_PER_GROUP(sb),
+ EXT2_INODES_PER_GROUP(sb),
+ sb->u.ext2_sb.s_mount_opt);
#ifdef CONFIG_EXT2_CHECK
- if (test_opt (sb, CHECK)) {
- ext2_check_blocks_bitmap (sb);
- ext2_check_inodes_bitmap (sb);
- }
-#endif
+ if (test_opt (sb, CHECK)) {
+ ext2_check_blocks_bitmap (sb);
+ ext2_check_inodes_bitmap (sb);
}
+#endif
+ return res;
}
static int ext2_check_descriptors (struct super_block * sb)
@@ -601,7 +604,7 @@ struct super_block * ext2_read_super (struct super_block * sb, void * data,
printk ("EXT2-fs: get root inode failed\n");
return NULL;
}
- ext2_setup_super (sb, es);
+ ext2_setup_super (sb, es, sb->s_flags & MS_RDONLY);
return sb;
}
@@ -685,8 +688,8 @@ int ext2_remount (struct super_block * sb, int * flags, char * data)
* by e2fsck since we originally mounted the partition.)
*/
sb->u.ext2_sb.s_mount_state = le16_to_cpu(es->s_state);
- sb->s_flags &= ~MS_RDONLY;
- ext2_setup_super (sb, es);
+ if (!ext2_setup_super (sb, es, 0))
+ sb->s_flags &= ~MS_RDONLY;
}
return 0;
}