Commit c6145b38 authored by Linus Torvalds's avatar Linus Torvalds

Import 0.99.14j

parent 27c43263
VERSION = 0.99 VERSION = 0.99
PATCHLEVEL = 14 PATCHLEVEL = 14
ALPHA = i ALPHA = j
all: Version zImage all: Version zImage
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
# #
# #
VERSION = 2.3 VERSION = 2.3b
TARGET_OS = linux TARGET_OS = linux
.c.s: .c.s:
......
...@@ -178,7 +178,7 @@ static int dsp_set_stereo(int mode) ...@@ -178,7 +178,7 @@ static int dsp_set_stereo(int mode)
{ {
DEB(printk("dsp_set_stereo(%d)\n",mode)); DEB(printk("dsp_set_stereo(%d)\n",mode));
if (mode) dsp_stereo=mode; dsp_stereo=mode;
return mode; return mode;
} }
......
/* /*
* linux/fs/ext2/acl.c * linux/fs/ext2/acl.c
* *
* Copyright (C) 1993 Remy Card (card@masi.ibp.fr) * Copyright (C) 1993, 1994 Remy Card (card@masi.ibp.fr)
* Laboratoire MASI - Institut Blaise Pascal
* Universite Pierre et Marie Curie (Paris VI)
*/ */
/* /*
...@@ -12,7 +14,6 @@ ...@@ -12,7 +14,6 @@
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/ext2_fs.h> #include <linux/ext2_fs.h>
#include <linux/kernel.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/stat.h> #include <linux/stat.h>
...@@ -25,10 +26,14 @@ int ext2_permission (struct inode * inode, int mask) ...@@ -25,10 +26,14 @@ int ext2_permission (struct inode * inode, int mask)
{ {
unsigned short mode = inode->i_mode; unsigned short mode = inode->i_mode;
/* Special case, access is always granted for root */ /*
* Special case, access is always granted for root
*/
if (suser ()) if (suser ())
return 1; return 1;
/* If no ACL, checks using the file mode */ /*
* If no ACL, checks using the file mode
*/
else if (current->euid == inode->i_uid) else if (current->euid == inode->i_uid)
mode >>= 6; mode >>= 6;
else if (in_group_p (inode->i_gid)) else if (in_group_p (inode->i_gid))
......
/* /*
* linux/fs/ext2/balloc.c * linux/fs/ext2/balloc.c
* *
* Copyright (C) 1992, 1993 Remy Card (card@masi.ibp.fr) * Copyright (C) 1992, 1993, 1994 Remy Card (card@masi.ibp.fr)
* Laboratoire MASI - Institut Blaise Pascal
* Universite Pierre et Marie Curie (Paris VI)
* *
* Enhanced block allocation by Stephen Tweedie (sct@dcs.ed.ac.uk), 1993 * Enhanced block allocation by Stephen Tweedie (sct@dcs.ed.ac.uk), 1993
*/ */
/* balloc.c contains the blocks allocation and deallocation routines */
/* /*
* balloc.c contains the blocks allocation and deallocation routines
*/
The free blocks are managed by bitmaps. A file system contains several /*
blocks groups. Each group contains 1 bitmap block for blocks, 1 bitmap * The free blocks are managed by bitmaps. A file system contains several
block for inodes, N blocks for the inode table and data blocks. * blocks groups. Each group contains 1 bitmap block for blocks, 1 bitmap
* block for inodes, N blocks for the inode table and data blocks.
The file system contains group descriptors which are located after the *
super block. Each descriptor contains the number of the bitmap block and * The file system contains group descriptors which are located after the
the free blocks count in the block. The descriptors are loaded in memory * super block. Each descriptor contains the number of the bitmap block and
when a file system is mounted (see ext2_read_super). * the free blocks count in the block. The descriptors are loaded in memory
* when a file system is mounted (see ext2_read_super).
*/ */
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/ext2_fs.h> #include <linux/ext2_fs.h>
#include <linux/kernel.h>
#include <linux/stat.h> #include <linux/stat.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/string.h> #include <linux/string.h>
...@@ -39,6 +40,8 @@ ...@@ -39,6 +40,8 @@
:"a" (0), "c" (size / 4), "D" ((long) (addr)) \ :"a" (0), "c" (size / 4), "D" ((long) (addr)) \
:"cx", "di") :"cx", "di")
#define in_range(b, first, len) ((b) >= (first) && (b) <= (first) + (len) - 1)
static inline int find_first_zero_bit (unsigned long * addr, unsigned size) static inline int find_first_zero_bit (unsigned long * addr, unsigned size)
{ {
int res; int res;
...@@ -72,7 +75,9 @@ static inline int find_next_zero_bit (unsigned long * addr, int size, ...@@ -72,7 +75,9 @@ static inline int find_next_zero_bit (unsigned long * addr, int size,
int set = 0, bit = offset & 31, res; int set = 0, bit = offset & 31, res;
if (bit) { if (bit) {
/* Look for zero in first byte */ /*
* Look for zero in first byte
*/
__asm__(" __asm__("
bsfl %1,%0 bsfl %1,%0
jne 1f jne 1f
...@@ -85,7 +90,9 @@ static inline int find_next_zero_bit (unsigned long * addr, int size, ...@@ -85,7 +90,9 @@ static inline int find_next_zero_bit (unsigned long * addr, int size,
set = 32 - bit; set = 32 - bit;
p++; p++;
} }
/* No zero yet, search remaining full bytes for a zero */ /*
* No zero yet, search remaining full bytes for a zero
*/
res = find_first_zero_bit (p, size - 32 * (p - addr)); res = find_first_zero_bit (p, size - 32 * (p - addr));
return (offset + set + res); return (offset + set + res);
} }
...@@ -109,32 +116,48 @@ static inline char * find_first_zero_byte (char * addr, int size) ...@@ -109,32 +116,48 @@ static inline char * find_first_zero_byte (char * addr, int size)
return res; return res;
} }
static void read_block_bitmap (struct super_block * sb, static struct ext2_group_desc * get_group_desc (struct super_block * sb,
unsigned int block_group, unsigned int block_group,
unsigned long bitmap_nr) struct buffer_head ** bh)
{ {
unsigned long group_desc; unsigned long group_desc;
unsigned long desc; unsigned long desc;
struct ext2_group_desc * gdp; struct ext2_group_desc * gdp;
struct buffer_head * bh;
if (block_group >= sb->u.ext2_sb.s_groups_count)
ext2_panic (sb, "get_group_desc",
"block_group >= groups_count\n"
"block_group = %d, groups_count = %lu",
block_group, sb->u.ext2_sb.s_groups_count);
group_desc = block_group / EXT2_DESC_PER_BLOCK(sb); group_desc = block_group / EXT2_DESC_PER_BLOCK(sb);
desc = block_group % EXT2_DESC_PER_BLOCK(sb); desc = block_group % EXT2_DESC_PER_BLOCK(sb);
if (!sb->u.ext2_sb.s_group_desc[group_desc]) if (!sb->u.ext2_sb.s_group_desc[group_desc])
ext2_panic (sb, "read_block_bitmap", ext2_panic (sb, "get_group_desc",
"Group descriptor not loaded\n" "Group descriptor not loaded\n"
"block_group = %d, group_desc = %lu, desc = %lu", "block_group = %d, group_desc = %lu, desc = %lu",
block_group, group_desc, desc); block_group, group_desc, desc);
gdp = (struct ext2_group_desc *) gdp = (struct ext2_group_desc *)
sb->u.ext2_sb.s_group_desc[group_desc]->b_data; sb->u.ext2_sb.s_group_desc[group_desc]->b_data;
bh = bread (sb->s_dev, gdp[desc].bg_block_bitmap, sb->s_blocksize); if (bh)
*bh = sb->u.ext2_sb.s_group_desc[group_desc];
return gdp + desc;
}
static void read_block_bitmap (struct super_block * sb,
unsigned int block_group,
unsigned long bitmap_nr)
{
struct ext2_group_desc * gdp;
struct buffer_head * bh;
gdp = get_group_desc (sb, block_group, NULL);
bh = bread (sb->s_dev, gdp->bg_block_bitmap, sb->s_blocksize);
if (!bh) if (!bh)
ext2_panic (sb, "read_block_bitmap", ext2_panic (sb, "read_block_bitmap",
"Cannot read block bitmap\n" "Cannot read block bitmap\n"
"block_group = %d, group_desc = %lu," "block_group = %d, block_bitmap = %lu",
"desc = %lu, block_bitmap = %lu", block_group, gdp->bg_block_bitmap);
block_group, group_desc, desc,
gdp[desc].bg_block_bitmap);
sb->u.ext2_sb.s_block_bitmap_number[bitmap_nr] = block_group; sb->u.ext2_sb.s_block_bitmap_number[bitmap_nr] = block_group;
sb->u.ext2_sb.s_block_bitmap[bitmap_nr] = bh; sb->u.ext2_sb.s_block_bitmap[bitmap_nr] = bh;
} }
...@@ -193,12 +216,10 @@ static int load__block_bitmap (struct super_block * sb, ...@@ -193,12 +216,10 @@ static int load__block_bitmap (struct super_block * sb,
sb->u.ext2_sb.s_block_bitmap_number[0] = block_bitmap_number; sb->u.ext2_sb.s_block_bitmap_number[0] = block_bitmap_number;
sb->u.ext2_sb.s_block_bitmap[0] = block_bitmap; sb->u.ext2_sb.s_block_bitmap[0] = block_bitmap;
} else { } else {
if (sb->u.ext2_sb.s_loaded_block_bitmaps < if (sb->u.ext2_sb.s_loaded_block_bitmaps < EXT2_MAX_GROUP_LOADED)
EXT2_MAX_GROUP_LOADED)
sb->u.ext2_sb.s_loaded_block_bitmaps++; sb->u.ext2_sb.s_loaded_block_bitmaps++;
else else
brelse (sb->u.ext2_sb.s_block_bitmap brelse (sb->u.ext2_sb.s_block_bitmap[EXT2_MAX_GROUP_LOADED - 1]);
[EXT2_MAX_GROUP_LOADED - 1]);
for (j = sb->u.ext2_sb.s_loaded_block_bitmaps - 1; j > 0; j--) { for (j = sb->u.ext2_sb.s_loaded_block_bitmaps - 1; j > 0; j--) {
sb->u.ext2_sb.s_block_bitmap_number[j] = sb->u.ext2_sb.s_block_bitmap_number[j] =
sb->u.ext2_sb.s_block_bitmap_number[j - 1]; sb->u.ext2_sb.s_block_bitmap_number[j - 1];
...@@ -225,64 +246,70 @@ static inline int load_block_bitmap (struct super_block * sb, ...@@ -225,64 +246,70 @@ static inline int load_block_bitmap (struct super_block * sb,
return load__block_bitmap (sb, block_group); return load__block_bitmap (sb, block_group);
} }
void ext2_free_block (struct super_block * sb, unsigned long block) void ext2_free_blocks (struct super_block * sb, unsigned long block,
unsigned long count)
{ {
struct buffer_head * bh; struct buffer_head * bh;
struct buffer_head * bh2; struct buffer_head * bh2;
unsigned long block_group; unsigned long block_group;
unsigned long bit; unsigned long bit;
unsigned long group_desc; unsigned long i;
unsigned long desc;
int bitmap_nr; int bitmap_nr;
struct ext2_group_desc * gdp; struct ext2_group_desc * gdp;
struct ext2_super_block * es; struct ext2_super_block * es;
if (!sb) { if (!sb) {
printk ("ext2_free_block: nonexistent device"); printk ("ext2_free_blocks: nonexistent device");
return; return;
} }
lock_super (sb); lock_super (sb);
es = sb->u.ext2_sb.s_es; es = sb->u.ext2_sb.s_es;
if (block < es->s_first_data_block || block >= es->s_blocks_count) { if (block < es->s_first_data_block ||
ext2_error (sb, "ext2_free_block", "block not in datazone"); (block + count) > es->s_blocks_count) {
ext2_error (sb, "ext2_free_blocks",
"Freeing blocks not in datazone");
unlock_super (sb); unlock_super (sb);
return; return;
} }
ext2_debug ("freeing block %lu\n", block); ext2_debug ("freeing block %lu\n", block);
#if 0 /* XXX - This is incompatible with the secure rm implemented in 0.4 */
bh = get_hash_table (sb->s_dev, block, sb->s_blocksize);
if (bh)
bh->b_dirt = 0;
brelse (bh);
#endif
block_group = (block - es->s_first_data_block) / block_group = (block - es->s_first_data_block) /
EXT2_BLOCKS_PER_GROUP(sb); EXT2_BLOCKS_PER_GROUP(sb);
bit = (block - es->s_first_data_block) % EXT2_BLOCKS_PER_GROUP(sb); bit = (block - es->s_first_data_block) % EXT2_BLOCKS_PER_GROUP(sb);
if (bit + count > EXT2_BLOCKS_PER_GROUP(sb))
ext2_panic (sb, "ext2_free_blocks",
"Freeing blocks across group boundary\n"
"Block = %lu, count = %lu",
block, count);
bitmap_nr = load_block_bitmap (sb, block_group); bitmap_nr = load_block_bitmap (sb, block_group);
bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr]; bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr];
if (!bh) gdp = get_group_desc (sb, block_group, &bh2);
ext2_panic (sb, "ext2_free_block",
"Unable to load group bitmap\n" if (test_opt (sb, CHECK_STRICT) &&
"block_group = %lu", block_group); (in_range (gdp->bg_block_bitmap, block, count) ||
if (!clear_bit (bit, bh->b_data)) in_range (gdp->bg_inode_bitmap, block, count) ||
ext2_warning (sb, "ext2_free_block", in_range (block, gdp->bg_inode_table,
"bit already cleared for block %lu", block); sb->u.ext2_sb.s_itb_per_group) ||
else { in_range (block + count - 1, gdp->bg_inode_table,
group_desc = block_group / EXT2_DESC_PER_BLOCK(sb); sb->u.ext2_sb.s_itb_per_group)))
desc = block_group % EXT2_DESC_PER_BLOCK(sb); ext2_panic (sb, "ext2_free_blocks",
bh2 = sb->u.ext2_sb.s_group_desc[group_desc]; "Freeing blocks in system zones\n"
if (!bh2) "Block = %lu, count = %lu",
ext2_panic (sb, "ext2_free_block", block, count);
"Group descriptor not loaded\n"
"group_desc = %lu", group_desc); for (i = 0; i < count; i++) {
gdp = (struct ext2_group_desc *) bh2->b_data; if (!clear_bit (bit + i, bh->b_data))
gdp[desc].bg_free_blocks_count++; ext2_warning (sb, "ext2_free_blocks",
"bit already cleared for block %lu",
block);
}
gdp->bg_free_blocks_count += count;
bh2->b_dirt = 1; bh2->b_dirt = 1;
es->s_free_blocks_count++; es->s_free_blocks_count += count;
sb->u.ext2_sb.s_sbh->b_dirt = 1; sb->u.ext2_sb.s_sbh->b_dirt = 1;
}
bh->b_dirt = 1; bh->b_dirt = 1;
if (sb->s_flags & MS_SYNC) { if (sb->s_flags & MS_SYNC) {
ll_rw_block (WRITE, 1, &bh); ll_rw_block (WRITE, 1, &bh);
...@@ -300,14 +327,15 @@ void ext2_free_block (struct super_block * sb, unsigned long block) ...@@ -300,14 +327,15 @@ void ext2_free_block (struct super_block * sb, unsigned long block)
* each block group the search first looks for an entire free byte in the block * each block group the search first looks for an entire free byte in the block
* bitmap, and then for any free bit if that fails. * bitmap, and then for any free bit if that fails.
*/ */
int ext2_new_block (struct super_block * sb, unsigned long goal) int ext2_new_block (struct super_block * sb, unsigned long goal,
unsigned long * prealloc_count,
unsigned long * prealloc_block)
{ {
struct buffer_head * bh; struct buffer_head * bh;
char *p, *r; struct buffer_head * bh2;
int i, j, k; char * p, * r;
int i, j, k, tmp;
unsigned long lmap; unsigned long lmap;
unsigned long group_desc;
unsigned long desc;
int bitmap_nr; int bitmap_nr;
struct ext2_group_desc * gdp; struct ext2_group_desc * gdp;
struct ext2_super_block * es; struct ext2_super_block * es;
...@@ -329,34 +357,21 @@ int ext2_new_block (struct super_block * sb, unsigned long goal) ...@@ -329,34 +357,21 @@ int ext2_new_block (struct super_block * sb, unsigned long goal)
ext2_debug ("goal=%lu.\n", goal); ext2_debug ("goal=%lu.\n", goal);
repeat: repeat:
/* First, test whether the goal block is free. */ /*
* First, test whether the goal block is free.
*/
i = ((goal - es->s_first_data_block) / EXT2_BLOCKS_PER_GROUP(sb)); i = ((goal - es->s_first_data_block) / EXT2_BLOCKS_PER_GROUP(sb));
group_desc = i / EXT2_DESC_PER_BLOCK(sb); gdp = get_group_desc (sb, i, &bh2);
desc = i % EXT2_DESC_PER_BLOCK(sb); if (gdp->bg_free_blocks_count > 0) {
gdp = (struct ext2_group_desc *) j = ((goal - es->s_first_data_block) % EXT2_BLOCKS_PER_GROUP(sb));
sb->u.ext2_sb.s_group_desc[group_desc]->b_data;
if (!gdp) {
ext2_panic (sb, "ext2_new_block",
"Descriptor not loaded for group %d", i);
}
if (gdp[desc].bg_free_blocks_count > 0) {
j = ((goal - es->s_first_data_block) %
EXT2_BLOCKS_PER_GROUP(sb));
#ifdef EXT2FS_DEBUG #ifdef EXT2FS_DEBUG
if (j) if (j)
goal_attempts++; goal_attempts++;
#endif #endif
bitmap_nr = load_block_bitmap (sb, i); bitmap_nr = load_block_bitmap (sb, i);
bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr]; bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr];
if (!bh) {
ext2_panic (sb, "ext2_new_block",
"Cannot load bitmap %d", bitmap_nr);
unlock_super (sb);
return 0;
}
ext2_debug ("goal is at %d[%lu,%lu]:%d.\n", i, group_desc, ext2_debug ("goal is at %d:%d.\n", i, j);
desc, j);
if (!test_bit(j, bh->b_data)) { if (!test_bit(j, bh->b_data)) {
#ifdef EXT2FS_DEBUG #ifdef EXT2FS_DEBUG
...@@ -366,8 +381,10 @@ int ext2_new_block (struct super_block * sb, unsigned long goal) ...@@ -366,8 +381,10 @@ int ext2_new_block (struct super_block * sb, unsigned long goal)
goto got_block; goto got_block;
} }
if (j) { if (j) {
/* The goal was occupied; search forward for a free /*
block within the next 32 blocks */ * The goal was occupied; search forward for a free
* block within the next 32 blocks
*/
lmap = ((((unsigned long *) bh->b_data)[j >> 5]) >> lmap = ((((unsigned long *) bh->b_data)[j >> 5]) >>
((j & 31) + 1)); ((j & 31) + 1));
if (j < EXT2_BLOCKS_PER_GROUP(sb) - 32) if (j < EXT2_BLOCKS_PER_GROUP(sb) - 32)
...@@ -389,20 +406,22 @@ int ext2_new_block (struct super_block * sb, unsigned long goal) ...@@ -389,20 +406,22 @@ int ext2_new_block (struct super_block * sb, unsigned long goal)
ext2_debug ("Bit not found near goal\n"); ext2_debug ("Bit not found near goal\n");
/* There has been no free block found in the near vicinity /*
of the goal: do a search forward through the block groups, * There has been no free block found in the near vicinity
searching in each group first for an entire free byte in * of the goal: do a search forward through the block groups,
the bitmap and then for any free bit. * searching in each group first for an entire free byte in
* the bitmap and then for any free bit.
Search first in the remainder of the current group; then, *
cyclicly search throught the rest of the groups. */ * Search first in the remainder of the current group; then,
* cyclicly search throught the rest of the groups.
*/
p = ((char *) bh->b_data) + (j >> 3); p = ((char *) bh->b_data) + (j >> 3);
r = find_first_zero_byte (p, r = find_first_zero_byte (p,
(EXT2_BLOCKS_PER_GROUP(sb) - j + 7) >> 3); (EXT2_BLOCKS_PER_GROUP(sb) - j + 7) >> 3);
k = (r - ((char *) bh->b_data)) << 3; k = (r - ((char *) bh->b_data)) << 3;
if (k < EXT2_BLOCKS_PER_GROUP(sb)) { if (k < EXT2_BLOCKS_PER_GROUP(sb)) {
j = k; j = k;
goto got_block; goto search_back;
} }
k = find_next_zero_bit ((unsigned long *) bh->b_data, k = find_next_zero_bit ((unsigned long *) bh->b_data,
EXT2_BLOCKS_PER_GROUP(sb), EXT2_BLOCKS_PER_GROUP(sb),
...@@ -415,32 +434,16 @@ int ext2_new_block (struct super_block * sb, unsigned long goal) ...@@ -415,32 +434,16 @@ int ext2_new_block (struct super_block * sb, unsigned long goal)
ext2_debug ("Bit not found in block group %d.\n", i); ext2_debug ("Bit not found in block group %d.\n", i);
/* Now search the rest of the groups. We assume that group_desc, desc, /*
i and gdp correctly point to the last group visited. */ * Now search the rest of the groups. We assume that
* i and gdp correctly point to the last group visited.
*/
for (k = 0; k < sb->u.ext2_sb.s_groups_count; k++) { for (k = 0; k < sb->u.ext2_sb.s_groups_count; k++) {
i++; i++;
if (i >= sb->u.ext2_sb.s_groups_count) { if (i >= sb->u.ext2_sb.s_groups_count)
i = 0; i = 0;
group_desc = 0; gdp = get_group_desc (sb, i, &bh2);
desc = 0; if (gdp->bg_free_blocks_count > 0)
gdp = (struct ext2_group_desc *)
sb->u.ext2_sb.s_group_desc[group_desc]->b_data;
}
else {
desc++;
if (desc >= EXT2_DESC_PER_BLOCK(sb)) {
group_desc++;
desc = 0;
gdp = (struct ext2_group_desc *)
sb->u.ext2_sb.s_group_desc[group_desc]
->b_data;
}
}
if (!gdp) {
ext2_panic (sb, "ext2_new_block",
"Descriptor not loaded for group %d", i);
}
if (gdp[desc].bg_free_blocks_count > 0)
break; break;
} }
if (k >= sb->u.ext2_sb.s_groups_count) { if (k >= sb->u.ext2_sb.s_groups_count) {
...@@ -449,13 +452,12 @@ int ext2_new_block (struct super_block * sb, unsigned long goal) ...@@ -449,13 +452,12 @@ int ext2_new_block (struct super_block * sb, unsigned long goal)
} }
bitmap_nr = load_block_bitmap (sb, i); bitmap_nr = load_block_bitmap (sb, i);
bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr]; bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr];
if (!bh)
ext2_panic (sb, "ext2_new_block",
"Unable to load bitmap for group %d", i);
r = find_first_zero_byte (bh->b_data, r = find_first_zero_byte (bh->b_data,
EXT2_BLOCKS_PER_GROUP(sb) >> 3); EXT2_BLOCKS_PER_GROUP(sb) >> 3);
j = (r - bh->b_data) << 3; j = (r - bh->b_data) << 3;
if (j >= EXT2_BLOCKS_PER_GROUP(sb)) if (j < EXT2_BLOCKS_PER_GROUP(sb))
goto search_back;
else
j = find_first_zero_bit ((unsigned long *) bh->b_data, j = find_first_zero_bit ((unsigned long *) bh->b_data,
EXT2_BLOCKS_PER_GROUP(sb)); EXT2_BLOCKS_PER_GROUP(sb));
if (j >= EXT2_BLOCKS_PER_GROUP(sb)) { if (j >= EXT2_BLOCKS_PER_GROUP(sb)) {
...@@ -465,25 +467,64 @@ int ext2_new_block (struct super_block * sb, unsigned long goal) ...@@ -465,25 +467,64 @@ int ext2_new_block (struct super_block * sb, unsigned long goal)
return 0; return 0;
} }
search_back:
/*
* We have succeeded in finding a free byte in the block
* bitmap. Now search backwards up to 7 bits to find the
* start of this group of free blocks.
*/
for (k = 0; k < 7 && j > 0 && !test_bit (j - 1, bh->b_data); k++, j--);
got_block: got_block:
ext2_debug ("using block group %d(%lu,%lu,%d)\n", ext2_debug ("using block group %d(%d)\n", i, gdp->bg_free_blocks_count);
i, group_desc, desc, gdp[desc].bg_free_blocks_count);
tmp = j + i * EXT2_BLOCKS_PER_GROUP(sb) + es->s_first_data_block;
if (test_opt (sb, CHECK_STRICT) &&
(tmp == gdp->bg_block_bitmap ||
tmp == gdp->bg_inode_bitmap ||
in_range (tmp, gdp->bg_inode_table, sb->u.ext2_sb.s_itb_per_group)))
ext2_panic (sb, "ext2_new_block",
"Allocating block in system zone\nblock = %u",
tmp);
if (set_bit (j, bh->b_data)) { if (set_bit (j, bh->b_data)) {
ext2_warning (sb, "ext2_new_block", ext2_warning (sb, "ext2_new_block",
"bit already set for block %d", j); "bit already set for block %d", j);
goto repeat; goto repeat;
} }
ext2_debug ("found bit %d\n", j);
/*
* Do block preallocation now if required.
*/
#ifdef EXT2_PREALLOCATE
if (prealloc_block) {
*prealloc_count = 0;
*prealloc_block = tmp + 1;
for (k = 1;
k < 8 && (j + k) < EXT2_BLOCKS_PER_GROUP(sb); k++) {
if (set_bit (j + k, bh->b_data))
break;
(*prealloc_count)++;
}
gdp->bg_free_blocks_count -= *prealloc_count;
es->s_free_blocks_count -= *prealloc_count;
ext2_debug ("Preallocated a further %lu bits.\n",
*prealloc_count);
}
#endif
j = tmp;
bh->b_dirt = 1; bh->b_dirt = 1;
if (sb->s_flags & MS_SYNC) { if (sb->s_flags & MS_SYNC) {
ll_rw_block (WRITE, 1, &bh); ll_rw_block (WRITE, 1, &bh);
wait_on_buffer (bh); wait_on_buffer (bh);
} }
ext2_debug ("found bit %d\n", j);
j += i * EXT2_BLOCKS_PER_GROUP(sb) + es->s_first_data_block;
if (j >= es->s_blocks_count) { if (j >= es->s_blocks_count) {
ext2_error (sb, "ext2_new_block", ext2_error (sb, "ext2_new_block",
"block >= blocks count\n" "block >= blocks count\n"
...@@ -504,8 +545,8 @@ int ext2_new_block (struct super_block * sb, unsigned long goal) ...@@ -504,8 +545,8 @@ int ext2_new_block (struct super_block * sb, unsigned long goal)
ext2_debug ("allocating block %d. " ext2_debug ("allocating block %d. "
"Goal hits %d of %d.\n", j, goal_hits, goal_attempts); "Goal hits %d of %d.\n", j, goal_hits, goal_attempts);
gdp[desc].bg_free_blocks_count--; gdp->bg_free_blocks_count--;
sb->u.ext2_sb.s_group_desc[group_desc]->b_dirt = 1; bh2->b_dirt = 1;
es->s_free_blocks_count--; es->s_free_blocks_count--;
sb->u.ext2_sb.s_sbh->b_dirt = 1; sb->u.ext2_sb.s_sbh->b_dirt = 1;
sb->s_dirt = 1; sb->s_dirt = 1;
...@@ -518,8 +559,6 @@ unsigned long ext2_count_free_blocks (struct super_block * sb) ...@@ -518,8 +559,6 @@ unsigned long ext2_count_free_blocks (struct super_block * sb)
#ifdef EXT2FS_DEBUG #ifdef EXT2FS_DEBUG
struct ext2_super_block * es; struct ext2_super_block * es;
unsigned long desc_count, bitmap_count, x; unsigned long desc_count, bitmap_count, x;
unsigned long group_desc;
unsigned long desc;
int bitmap_nr; int bitmap_nr;
struct ext2_group_desc * gdp; struct ext2_group_desc * gdp;
int i; int i;
...@@ -528,38 +567,16 @@ unsigned long ext2_count_free_blocks (struct super_block * sb) ...@@ -528,38 +567,16 @@ unsigned long ext2_count_free_blocks (struct super_block * sb)
es = sb->u.ext2_sb.s_es; es = sb->u.ext2_sb.s_es;
desc_count = 0; desc_count = 0;
bitmap_count = 0; bitmap_count = 0;
group_desc = 0;
desc = 0;
gdp = NULL; gdp = NULL;
for (i = 0; i < sb->u.ext2_sb.s_groups_count; i++) { for (i = 0; i < sb->u.ext2_sb.s_groups_count; i++) {
if (!gdp) { gdp = get_group_desc (sb, i, NULL);
if (!sb->u.ext2_sb.s_group_desc[group_desc]) { desc_count += gdp->bg_free_blocks_count;
printk ("ext2_count_free_block: "
"Descriptor not loaded\n");
break;
}
gdp = (struct ext2_group_desc *)
sb->u.ext2_sb.s_group_desc[group_desc]->b_data;
}
desc_count += gdp[desc].bg_free_blocks_count;
bitmap_nr = load_block_bitmap (sb, i); bitmap_nr = load_block_bitmap (sb, i);
if (sb->u.ext2_sb.s_block_bitmap[bitmap_nr]) x = ext2_count_free (sb->u.ext2_sb.s_block_bitmap[bitmap_nr],
x = ext2_count_free
(sb->u.ext2_sb.s_block_bitmap[bitmap_nr],
sb->s_blocksize); sb->s_blocksize);
else {
x = 0;
printk ("Cannot load bitmap for group %d\n", i);
}
printk ("group %d: stored = %d, counted = %lu\n", printk ("group %d: stored = %d, counted = %lu\n",
i, gdp[desc].bg_free_blocks_count, x); i, gdp->bg_free_blocks_count, x);
bitmap_count += x; bitmap_count += x;
desc++;
if (desc == EXT2_DESC_PER_BLOCK(sb)) {
group_desc++;
desc = 0;
gdp = NULL;
}
} }
printk("ext2_count_free_blocks: stored = %lu, computed = %lu, %lu\n", printk("ext2_count_free_blocks: stored = %lu, computed = %lu, %lu\n",
es->s_free_blocks_count, desc_count, bitmap_count); es->s_free_blocks_count, desc_count, bitmap_count);
...@@ -570,57 +587,57 @@ unsigned long ext2_count_free_blocks (struct super_block * sb) ...@@ -570,57 +587,57 @@ unsigned long ext2_count_free_blocks (struct super_block * sb)
#endif #endif
} }
static inline int block_in_use (unsigned long block,
struct super_block * sb,
unsigned char * map)
{
return test_bit ((block - sb->u.ext2_sb.s_es->s_first_data_block) %
EXT2_BLOCKS_PER_GROUP(sb), map);
}
void ext2_check_blocks_bitmap (struct super_block * sb) void ext2_check_blocks_bitmap (struct super_block * sb)
{ {
struct buffer_head * bh;
struct ext2_super_block * es; struct ext2_super_block * es;
unsigned long desc_count, bitmap_count, x; unsigned long desc_count, bitmap_count, x;
unsigned long group_desc;
unsigned long desc;
int bitmap_nr; int bitmap_nr;
struct ext2_group_desc * gdp; struct ext2_group_desc * gdp;
int i; int i, j;
lock_super (sb); lock_super (sb);
es = sb->u.ext2_sb.s_es; es = sb->u.ext2_sb.s_es;
desc_count = 0; desc_count = 0;
bitmap_count = 0; bitmap_count = 0;
group_desc = 0;
desc = 0;
gdp = NULL; gdp = NULL;
for (i = 0; i < sb->u.ext2_sb.s_groups_count; i++) { for (i = 0; i < sb->u.ext2_sb.s_groups_count; i++) {
if (!gdp) { gdp = get_group_desc (sb, i, NULL);
if (!sb->u.ext2_sb.s_group_desc[group_desc]) { desc_count += gdp->bg_free_blocks_count;
bitmap_nr = load_block_bitmap (sb, i);
bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr];
if (!block_in_use (gdp->bg_block_bitmap, sb, bh->b_data))
ext2_error (sb, "ext2_check_blocks_bitmap", ext2_error (sb, "ext2_check_blocks_bitmap",
"Descriptor not loaded for group %d", "Block bitmap for group %d is marked free",
i); i);
break;
} if (!block_in_use (gdp->bg_inode_bitmap, sb, bh->b_data))
gdp = (struct ext2_group_desc *)
sb->u.ext2_sb.s_group_desc[group_desc]->b_data;
}
desc_count += gdp[desc].bg_free_blocks_count;
bitmap_nr = load_block_bitmap (sb, i);
if (sb->u.ext2_sb.s_block_bitmap[bitmap_nr])
x = ext2_count_free
(sb->u.ext2_sb.s_block_bitmap[bitmap_nr],
sb->s_blocksize);
else {
x = 0;
ext2_error (sb, "ext2_check_blocks_bitmap", ext2_error (sb, "ext2_check_blocks_bitmap",
"Cannot load bitmap for group %d\n", i); "Inode bitmap for group %d is marked free",
} i);
if (gdp[desc].bg_free_blocks_count != x)
for (j = 0; j < sb->u.ext2_sb.s_itb_per_group; j++)
if (!block_in_use (gdp->bg_inode_table + j, sb, bh->b_data))
ext2_error (sb, "ext2_check_blocks_bitmap",
"Block #%d of the inode table in group %d "
"is marked free", j, i);
x = ext2_count_free (bh, sb->s_blocksize);
if (gdp->bg_free_blocks_count != x)
ext2_error (sb, "ext2_check_blocks_bitmap", ext2_error (sb, "ext2_check_blocks_bitmap",
"Wrong free blocks count for group %d, " "Wrong free blocks count for group %d, "
"stored = %d, counted = %lu", i, "stored = %d, counted = %lu", i,
gdp[desc].bg_free_blocks_count, x); gdp->bg_free_blocks_count, x);
bitmap_count += x; bitmap_count += x;
desc++;
if (desc == EXT2_DESC_PER_BLOCK(sb)) {
group_desc++;
desc = 0;
gdp = NULL;
}
} }
if (es->s_free_blocks_count != bitmap_count) if (es->s_free_blocks_count != bitmap_count)
ext2_error (sb, "ext2_check_blocks_bitmap", ext2_error (sb, "ext2_check_blocks_bitmap",
......
/* /*
* linux/fs/ext2/bitmap.c * linux/fs/ext2/bitmap.c
* *
* Copyright (C) 1992, 1993 Remy Card (card@masi.ibp.fr) * Copyright (C) 1992, 1993, 1994 Remy Card (card@masi.ibp.fr)
* Laboratoire MASI - Institut Blaise Pascal
* Universite Pierre et Marie Curie (Paris VI)
*/ */
#include <linux/fs.h> #include <linux/fs.h>
......
/* /*
* linux/fs/ext2/dcache.c * linux/fs/ext2/dcache.c
* *
* Copyright (C) 1992, 1993 Remy Card (card@masi.ibp.fr) * Copyright (C) 1992, 1993, 1994 Remy Card (card@masi.ibp.fr)
* Laboratoire MASI - Institut Blaise Pascal
* Universite Pierre et Marie Curie (Paris VI)
* *
*/ */
...@@ -14,7 +16,6 @@ ...@@ -14,7 +16,6 @@
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/ext2_fs.h> #include <linux/ext2_fs.h>
#include <linux/kernel.h>
#include <linux/string.h> #include <linux/string.h>
#ifndef DONT_USE_DCACHE #ifndef DONT_USE_DCACHE
......
/* /*
* linux/fs/ext2/dir.c * linux/fs/ext2/dir.c
* *
* Copyright (C) 1992, 1993 Remy Card (card@masi.ibp.fr) * Copyright (C) 1992, 1993, 1994 Remy Card (card@masi.ibp.fr)
* Laboratoire MASI - Institut Blaise Pascal
* Universite Pierre et Marie Curie (Paris VI)
* *
* from * from
* *
...@@ -14,26 +16,32 @@ ...@@ -14,26 +16,32 @@
#include <asm/segment.h> #include <asm/segment.h>
#include <linux/autoconf.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/ext2_fs.h> #include <linux/ext2_fs.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/stat.h> #include <linux/stat.h>
#if 0 #ifndef CONFIG_EXT2_FS_DIR_READ
static int ext2_dir_read (struct inode * inode, struct file * filp, static int ext2_dir_read (struct inode * inode, struct file * filp,
char * buf, int count) char * buf, int count)
{ {
return -EISDIR; return -EISDIR;
} }
#else
int ext2_file_read (struct inode *, struct file *, char *, int);
#endif #endif
/* static */ int ext2_file_read (struct inode *, struct file *, char *, int);
static int ext2_readdir (struct inode *, struct file *, struct dirent *, int); static int ext2_readdir (struct inode *, struct file *, struct dirent *, int);
static struct file_operations ext2_dir_operations = { static struct file_operations ext2_dir_operations = {
NULL, /* lseek - default */ NULL, /* lseek - default */
#ifdef CONFIG_EXT2_FS_DIR_READ
ext2_file_read, /* read */ ext2_file_read, /* read */
#else
ext2_dir_read, /* read */
#endif
NULL, /* write - bad */ NULL, /* write - bad */
ext2_readdir, /* readdir */ ext2_readdir, /* readdir */
NULL, /* select - default */ NULL, /* select - default */
...@@ -92,9 +100,9 @@ int ext2_check_dir_entry (char * function, struct inode * dir, ...@@ -92,9 +100,9 @@ int ext2_check_dir_entry (char * function, struct inode * dir,
static int ext2_readdir (struct inode * inode, struct file * filp, static int ext2_readdir (struct inode * inode, struct file * filp,
struct dirent * dirent, int count) struct dirent * dirent, int count)
{ {
unsigned long offset; unsigned long offset, blk;
int i; int i, num;
struct buffer_head * bh; struct buffer_head * bh, * tmp, * bha[16];
struct ext2_dir_entry * de; struct ext2_dir_entry * de;
struct super_block * sb; struct super_block * sb;
int err; int err;
...@@ -104,15 +112,35 @@ static int ext2_readdir (struct inode * inode, struct file * filp, ...@@ -104,15 +112,35 @@ static int ext2_readdir (struct inode * inode, struct file * filp,
sb = inode->i_sb; sb = inode->i_sb;
while (filp->f_pos < inode->i_size) { while (filp->f_pos < inode->i_size) {
offset = filp->f_pos & (sb->s_blocksize - 1); offset = filp->f_pos & (sb->s_blocksize - 1);
bh = ext2_bread (inode, (filp->f_pos) >> EXT2_BLOCK_SIZE_BITS(sb), blk = (filp->f_pos) >> EXT2_BLOCK_SIZE_BITS(sb);
0, &err); bh = ext2_bread (inode, blk, 0, &err);
if (!bh) { if (!bh) {
filp->f_pos += sb->s_blocksize - offset; filp->f_pos += sb->s_blocksize - offset;
continue; continue;
} }
/*
* Do the readahead
*/
if (!offset) {
for (i = 16 >> (EXT2_BLOCK_SIZE_BITS(sb) - 9), num = 0;
i > 0; i--) {
tmp = ext2_getblk (inode, ++blk, 0, &err);
if (tmp && !tmp->b_uptodate && !tmp->b_lock)
bha[num++] = tmp;
else
brelse (tmp);
}
if (num) {
ll_rw_block (READA, num, bha);
for (i = 0; i < num; i++)
brelse (bha[i]);
}
}
de = (struct ext2_dir_entry *) (offset + bh->b_data); de = (struct ext2_dir_entry *) (offset + bh->b_data);
while (offset < sb->s_blocksize && filp->f_pos < inode->i_size) { while (offset < sb->s_blocksize && filp->f_pos < inode->i_size) {
if (! ext2_check_dir_entry ("ext2_readdir", inode, de, if (!ext2_check_dir_entry ("ext2_readdir", inode, de,
bh, offset)) { bh, offset)) {
brelse (bh); brelse (bh);
return 0; return 0;
......
/* /*
* linux/fs/ext2/file.c * linux/fs/ext2/file.c
* *
* Copyright (C) 1992, 1993 Remy Card (card@masi.ibp.fr) * Copyright (C) 1992, 1993, 1994 Remy Card (card@masi.ibp.fr)
* Laboratoire MASI - Institut Blaise Pascal
* Universite Pierre et Marie Curie (Paris VI)
* *
* from * from
* *
...@@ -15,11 +17,11 @@ ...@@ -15,11 +17,11 @@
#include <asm/segment.h> #include <asm/segment.h>
#include <asm/system.h> #include <asm/system.h>
#include <linux/autoconf.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/ext2_fs.h> #include <linux/ext2_fs.h>
#include <linux/fcntl.h> #include <linux/fcntl.h>
#include <linux/kernel.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/stat.h> #include <linux/stat.h>
#include <linux/locks.h> #include <linux/locks.h>
...@@ -32,8 +34,12 @@ ...@@ -32,8 +34,12 @@
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/ext2_fs.h> #include <linux/ext2_fs.h>
/* static */ int ext2_file_read (struct inode *, struct file *, char *, int); #ifndef CONFIG_EXT2_FS_DIR_READ
static
#endif
int ext2_file_read (struct inode *, struct file *, char *, int);
static int ext2_file_write (struct inode *, struct file *, char *, int); static int ext2_file_write (struct inode *, struct file *, char *, int);
static void ext2_release_file (struct inode *, struct file *);
/* /*
* We have mostly NULL's here: the current defaults are ok for * We have mostly NULL's here: the current defaults are ok for
...@@ -48,7 +54,7 @@ static struct file_operations ext2_file_operations = { ...@@ -48,7 +54,7 @@ static struct file_operations ext2_file_operations = {
ext2_ioctl, /* ioctl */ ext2_ioctl, /* ioctl */
generic_mmap, /* mmap */ generic_mmap, /* mmap */
NULL, /* no special open is needed */ NULL, /* no special open is needed */
NULL, /* release */ ext2_release_file, /* release */
ext2_sync_file /* fsync */ ext2_sync_file /* fsync */
}; };
...@@ -70,7 +76,10 @@ struct inode_operations ext2_file_inode_operations = { ...@@ -70,7 +76,10 @@ struct inode_operations ext2_file_inode_operations = {
ext2_permission /* permission */ ext2_permission /* permission */
}; };
/* static */ int ext2_file_read (struct inode * inode, struct file * filp, #ifndef CONFIG_EXT2_FS_DIR_READ
static
#endif
int ext2_file_read (struct inode * inode, struct file * filp,
char * buf, int count) char * buf, int count)
{ {
int read, left, chars; int read, left, chars;
...@@ -116,15 +125,17 @@ struct inode_operations ext2_file_inode_operations = { ...@@ -116,15 +125,17 @@ struct inode_operations ext2_file_inode_operations = {
blocks = size - block; blocks = size - block;
} }
/* We do this in a two stage process. We first try and request /*
as many blocks as we can, then we wait for the first one to * We do this in a two stage process. We first try and request
complete, and then we try and wrap up as many as are actually * as many blocks as we can, then we wait for the first one to
done. This routine is rather generic, in that it can be used * complete, and then we try and wrap up as many as are actually
in a filesystem by substituting the appropriate function in * done. This routine is rather generic, in that it can be used
for getblk * in a filesystem by substituting the appropriate function in
* for getblk
This routine is optimized to make maximum use of the various *
buffers and caches. */ * This routine is optimized to make maximum use of the various
* buffers and caches.
*/
do { do {
bhrequest = 0; bhrequest = 0;
...@@ -140,8 +151,10 @@ struct inode_operations ext2_file_inode_operations = { ...@@ -140,8 +151,10 @@ struct inode_operations ext2_file_inode_operations = {
if (++bhb == &buflist[NBUF]) if (++bhb == &buflist[NBUF])
bhb = buflist; bhb = buflist;
/* If the block we have on hand is uptodate, go ahead /*
and complete processing */ * If the block we have on hand is uptodate, go ahead
* and complete processing
*/
if (uptodate) if (uptodate)
break; break;
...@@ -149,11 +162,16 @@ struct inode_operations ext2_file_inode_operations = { ...@@ -149,11 +162,16 @@ struct inode_operations ext2_file_inode_operations = {
break; break;
} }
/* Now request them all */ /*
* Now request them all
*/
if (bhrequest) if (bhrequest)
ll_rw_block (READ, bhrequest, bhreq); ll_rw_block (READ, bhrequest, bhreq);
do { /* Finish off all I/O that has actually completed */ do {
/*
* Finish off all I/O that has actually completed
*/
if (*bhe) { if (*bhe) {
wait_on_buffer (*bhe); wait_on_buffer (*bhe);
if (!(*bhe)->b_uptodate) { /* read error? */ if (!(*bhe)->b_uptodate) { /* read error? */
...@@ -186,7 +204,9 @@ struct inode_operations ext2_file_inode_operations = { ...@@ -186,7 +204,9 @@ struct inode_operations ext2_file_inode_operations = {
} while (left > 0 && bhe != bhb && (!*bhe || !(*bhe)->b_lock)); } while (left > 0 && bhe != bhb && (!*bhe || !(*bhe)->b_lock));
} while (left > 0); } while (left > 0);
/* Release the read-ahead blocks */ /*
* Release the read-ahead blocks
*/
while (bhe != bhb) { while (bhe != bhb) {
brelse (*bhe); brelse (*bhe);
if (++bhe == &buflist[NBUF]) if (++bhe == &buflist[NBUF])
...@@ -217,6 +237,12 @@ static int ext2_file_write (struct inode * inode, struct file * filp, ...@@ -217,6 +237,12 @@ static int ext2_file_write (struct inode * inode, struct file * filp,
return -EINVAL; return -EINVAL;
} }
sb = inode->i_sb; sb = inode->i_sb;
if (sb->s_flags & MS_RDONLY)
/*
* This fs has been automatically remounted ro because of errors
*/
return -ENOSPC;
if (!S_ISREG(inode->i_mode)) { if (!S_ISREG(inode->i_mode)) {
ext2_warning (sb, "ext2_file_write", "mode = %07o\n", ext2_warning (sb, "ext2_file_write", "mode = %07o\n",
inode->i_mode); inode->i_mode);
...@@ -269,3 +295,14 @@ static int ext2_file_write (struct inode * inode, struct file * filp, ...@@ -269,3 +295,14 @@ static int ext2_file_write (struct inode * inode, struct file * filp,
inode->i_dirt = 1; inode->i_dirt = 1;
return written; return written;
} }
/*
* Called when a inode is released. Note that this is different
* from ext2_open: open gets called at every open, but release
* gets called only when /all/ the files are closed.
*/
static void ext2_release_file (struct inode * inode, struct file * filp)
{
if (filp->f_mode & 2)
ext2_discard_prealloc (inode);
}
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
* Copyright (C) 1993 Stephen Tweedie (sct@dcs.ed.ac.uk) * Copyright (C) 1993 Stephen Tweedie (sct@dcs.ed.ac.uk)
* from * from
* Copyright (C) 1992 Remy Card (card@masi.ibp.fr) * Copyright (C) 1992 Remy Card (card@masi.ibp.fr)
* Laboratoire MASI - Institut Blaise Pascal
* Universite Pierre et Marie Curie (Paris VI)
* from * from
* linux/fs/minix/truncate.c Copyright (C) 1991, 1992 Linus Torvalds * linux/fs/minix/truncate.c Copyright (C) 1991, 1992 Linus Torvalds
* *
...@@ -171,8 +173,10 @@ int ext2_sync_file (struct inode * inode, struct file * file) ...@@ -171,8 +173,10 @@ int ext2_sync_file (struct inode * inode, struct file * file)
if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
S_ISLNK(inode->i_mode))) S_ISLNK(inode->i_mode)))
return -EINVAL; return -EINVAL;
/* Don't sync fast links! */
if (S_ISLNK(inode->i_mode) && !(inode->i_blocks)) if (S_ISLNK(inode->i_mode) && !(inode->i_blocks))
/*
* Don't sync fast links!
*/
goto skip; goto skip;
for (wait=0; wait<=1; wait++) for (wait=0; wait<=1; wait++)
......
/* /*
* linux/fs/ext2/ialloc.c * linux/fs/ext2/ialloc.c
* *
* Copyright (C) 1992, 1993 Remy Card (card@masi.ibp.fr) * Copyright (C) 1992, 1993, 1994 Remy Card (card@masi.ibp.fr)
* Laboratoire MASI - Institut Blaise Pascal
* Universite Pierre et Marie Curie (Paris VI)
* *
* BSD ufs-inspired inode and directory allocation by * BSD ufs-inspired inode and directory allocation by
* Stephen Tweedie (sct@dcs.ed.ac.uk), 1993 * Stephen Tweedie (sct@dcs.ed.ac.uk), 1993
*/ */
/* ialloc.c contains the inodes allocation and deallocation routines */
/* /*
* ialloc.c contains the inodes allocation and deallocation routines
*/
The free inodes are managed by bitmaps. A file system contains several /*
blocks groups. Each group contains 1 bitmap block for blocks, 1 bitmap * The free inodes are managed by bitmaps. A file system contains several
block for inodes, N blocks for the inode table and data blocks. * blocks groups. Each group contains 1 bitmap block for blocks, 1 bitmap
* block for inodes, N blocks for the inode table and data blocks.
The file system contains group descriptors which are located after the *
super block. Each descriptor contains the number of the bitmap block and * The file system contains group descriptors which are located after the
the free blocks count in the block. The descriptors are loaded in memory * super block. Each descriptor contains the number of the bitmap block and
when a file system is mounted (see ext2_read_super). * the free blocks count in the block. The descriptors are loaded in memory
* when a file system is mounted (see ext2_read_super).
*/ */
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/ext2_fs.h> #include <linux/ext2_fs.h>
#include <linux/kernel.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/stat.h> #include <linux/stat.h>
#include <linux/string.h> #include <linux/string.h>
...@@ -59,28 +59,47 @@ static inline int find_first_zero_bit (unsigned long * addr, unsigned size) ...@@ -59,28 +59,47 @@ static inline int find_first_zero_bit (unsigned long * addr, unsigned size)
return res; return res;
} }
static void read_inode_bitmap (struct super_block * sb, static struct ext2_group_desc * get_group_desc (struct super_block * sb,
unsigned long block_group, unsigned int block_group,
unsigned int bitmap_nr) struct buffer_head ** bh)
{ {
unsigned long group_desc; unsigned long group_desc;
unsigned long desc; unsigned long desc;
struct ext2_group_desc * gdp; struct ext2_group_desc * gdp;
struct buffer_head * bh;
if (block_group >= sb->u.ext2_sb.s_groups_count)
ext2_panic (sb, "get_group_desc",
"block_group >= groups_count\n"
"block_group = %d, groups_count = %lu",
block_group, sb->u.ext2_sb.s_groups_count);
group_desc = block_group / EXT2_DESC_PER_BLOCK(sb); group_desc = block_group / EXT2_DESC_PER_BLOCK(sb);
desc = block_group % EXT2_DESC_PER_BLOCK(sb); desc = block_group % EXT2_DESC_PER_BLOCK(sb);
if (!sb->u.ext2_sb.s_group_desc[group_desc]) if (!sb->u.ext2_sb.s_group_desc[group_desc])
ext2_panic (sb, "read_inode_bitmap", ext2_panic (sb, "get_group_desc",
"Group descriptor not loaded\n" "Group descriptor not loaded\n"
"block_group = %lu, group_desc = %lu, desc = %lu", "block_group = %d, group_desc = %lu, desc = %lu",
block_group, group_desc, desc); block_group, group_desc, desc);
gdp = (struct ext2_group_desc *) sb->u.ext2_sb.s_group_desc[group_desc]->b_data; gdp = (struct ext2_group_desc *)
bh = bread (sb->s_dev, gdp[desc].bg_inode_bitmap, sb->s_blocksize); sb->u.ext2_sb.s_group_desc[group_desc]->b_data;
if (bh)
*bh = sb->u.ext2_sb.s_group_desc[group_desc];
return gdp + desc;
}
static void read_inode_bitmap (struct super_block * sb,
unsigned long block_group,
unsigned int bitmap_nr)
{
struct ext2_group_desc * gdp;
struct buffer_head * bh;
gdp = get_group_desc (sb, block_group, NULL);
bh = bread (sb->s_dev, gdp->bg_inode_bitmap, sb->s_blocksize);
if (!bh) if (!bh)
ext2_panic (sb, "read_inode_bitmap", "Cannot read inode bitmap\n" ext2_panic (sb, "read_inode_bitmap", "Cannot read inode bitmap\n"
"block_group = %lu, group_desc = %lu, desc = %lu, inode_bitmap = %lu", "block_group = %lu, inode_bitmap = %lu",
block_group, group_desc, desc, gdp[desc].bg_inode_bitmap); block_group, gdp->bg_inode_bitmap);
sb->u.ext2_sb.s_inode_bitmap_number[bitmap_nr] = block_group; sb->u.ext2_sb.s_inode_bitmap_number[bitmap_nr] = block_group;
sb->u.ext2_sb.s_inode_bitmap[bitmap_nr] = bh; sb->u.ext2_sb.s_inode_bitmap[bitmap_nr] = bh;
} }
...@@ -162,13 +181,13 @@ static int load_inode_bitmap (struct super_block * sb, ...@@ -162,13 +181,13 @@ static int load_inode_bitmap (struct super_block * sb,
* This may be used one day by an 'undelete' program * This may be used one day by an 'undelete' program
*/ */
static void set_inode_dtime (struct inode * inode, static void set_inode_dtime (struct inode * inode,
struct ext2_group_desc * gdp, unsigned long desc) struct ext2_group_desc * gdp)
{ {
unsigned long inode_block; unsigned long inode_block;
struct buffer_head * bh; struct buffer_head * bh;
struct ext2_inode * raw_inode; struct ext2_inode * raw_inode;
inode_block = gdp[desc].bg_inode_table + (((inode->i_ino - 1) % inode_block = gdp->bg_inode_table + (((inode->i_ino - 1) %
EXT2_INODES_PER_GROUP(inode->i_sb)) / EXT2_INODES_PER_GROUP(inode->i_sb)) /
EXT2_INODES_PER_BLOCK(inode->i_sb)); EXT2_INODES_PER_BLOCK(inode->i_sb));
bh = bread (inode->i_sb->s_dev, inode_block, inode->i_sb->s_blocksize); bh = bread (inode->i_sb->s_dev, inode_block, inode->i_sb->s_blocksize);
...@@ -198,8 +217,6 @@ void ext2_free_inode (struct inode * inode) ...@@ -198,8 +217,6 @@ void ext2_free_inode (struct inode * inode)
struct buffer_head * bh2; struct buffer_head * bh2;
unsigned long block_group; unsigned long block_group;
unsigned long bit; unsigned long bit;
unsigned long group_desc;
unsigned long desc;
int bitmap_nr; int bitmap_nr;
struct ext2_group_desc * gdp; struct ext2_group_desc * gdp;
struct ext2_super_block * es; struct ext2_super_block * es;
...@@ -241,28 +258,18 @@ void ext2_free_inode (struct inode * inode) ...@@ -241,28 +258,18 @@ void ext2_free_inode (struct inode * inode)
bit = (inode->i_ino - 1) % EXT2_INODES_PER_GROUP(sb); bit = (inode->i_ino - 1) % EXT2_INODES_PER_GROUP(sb);
bitmap_nr = load_inode_bitmap (sb, block_group); bitmap_nr = load_inode_bitmap (sb, block_group);
bh = sb->u.ext2_sb.s_inode_bitmap[bitmap_nr]; bh = sb->u.ext2_sb.s_inode_bitmap[bitmap_nr];
if (!bh)
ext2_panic (sb, "ext2_free_inode",
"Unable to load bitmap for group %lu", block_group);
if (!clear_bit (bit, bh->b_data)) if (!clear_bit (bit, bh->b_data))
ext2_warning (sb, "ext2_free_inode", ext2_warning (sb, "ext2_free_inode",
"bit already cleared for inode %lu", inode->i_ino); "bit already cleared for inode %lu", inode->i_ino);
else { else {
group_desc = block_group / EXT2_DESC_PER_BLOCK(sb); gdp = get_group_desc (sb, block_group, &bh2);
desc = block_group % EXT2_DESC_PER_BLOCK(sb); gdp->bg_free_inodes_count++;
bh2 = sb->u.ext2_sb.s_group_desc[group_desc];
if (!bh2)
ext2_panic (sb, "ext2_free_inode",
"Group descriptor not loaded for group %lu",
group_desc);
gdp = (struct ext2_group_desc *) bh2->b_data;
gdp[desc].bg_free_inodes_count++;
if (S_ISDIR(inode->i_mode)) if (S_ISDIR(inode->i_mode))
gdp[desc].bg_used_dirs_count--; gdp->bg_used_dirs_count--;
bh2->b_dirt = 1; bh2->b_dirt = 1;
es->s_free_inodes_count++; es->s_free_inodes_count++;
sb->u.ext2_sb.s_sbh->b_dirt = 1; sb->u.ext2_sb.s_sbh->b_dirt = 1;
set_inode_dtime (inode, gdp, desc); set_inode_dtime (inode, gdp);
} }
bh->b_dirt = 1; bh->b_dirt = 1;
if (sb->s_flags & MS_SYNC) { if (sb->s_flags & MS_SYNC) {
...@@ -310,22 +317,6 @@ static void inc_inode_version (struct inode * inode, ...@@ -310,22 +317,6 @@ static void inc_inode_version (struct inode * inode,
brelse (bh); brelse (bh);
} }
static struct ext2_group_desc * get_group_desc (struct super_block * sb,
int group)
{
struct ext2_group_desc * gdp;
if (group >= sb->u.ext2_sb.s_groups_count || group < 0 )
ext2_panic (sb, "get_group_desc", "Invalid group %d", group);
if (!sb->u.ext2_sb.s_group_desc[group / EXT2_DESC_PER_BLOCK(sb)])
ext2_panic (sb, "get_group_desc",
"Descriptor not loaded for group %d", group);
gdp = (struct ext2_group_desc *)
sb->u.ext2_sb.s_group_desc[group / EXT2_DESC_PER_BLOCK(sb)]
->b_data;
return gdp + (group % EXT2_DESC_PER_BLOCK(sb));
}
/* /*
* There are two policies for allocating an inode. If the new inode is * There are two policies for allocating an inode. If the new inode is
* a directory, then a forward search is made for a block group with both * a directory, then a forward search is made for a block group with both
...@@ -340,10 +331,12 @@ struct inode * ext2_new_inode (const struct inode * dir, int mode) ...@@ -340,10 +331,12 @@ struct inode * ext2_new_inode (const struct inode * dir, int mode)
{ {
struct super_block * sb; struct super_block * sb;
struct buffer_head * bh; struct buffer_head * bh;
struct buffer_head * bh2;
int i, j, avefreei; int i, j, avefreei;
struct inode * inode; struct inode * inode;
int bitmap_nr; int bitmap_nr;
struct ext2_group_desc * gdp, * tmp; struct ext2_group_desc * gdp;
struct ext2_group_desc * tmp;
struct ext2_super_block * es; struct ext2_super_block * es;
if (!dir || !(inode = get_empty_inode ())) if (!dir || !(inode = get_empty_inode ()))
...@@ -362,7 +355,7 @@ struct inode * ext2_new_inode (const struct inode * dir, int mode) ...@@ -362,7 +355,7 @@ struct inode * ext2_new_inode (const struct inode * dir, int mode)
/* I am not yet convinced that this next bit is necessary. /* I am not yet convinced that this next bit is necessary.
i = dir->u.ext2_i.i_block_group; i = dir->u.ext2_i.i_block_group;
for (j = 0; j < sb->u.ext2_sb.s_groups_count; j++) { for (j = 0; j < sb->u.ext2_sb.s_groups_count; j++) {
tmp = get_group_desc (sb, i); tmp = get_group_desc (sb, i, &bh2);
if ((tmp->bg_used_dirs_count << 8) < if ((tmp->bg_used_dirs_count << 8) <
tmp->bg_free_inodes_count) { tmp->bg_free_inodes_count) {
gdp = tmp; gdp = tmp;
...@@ -374,12 +367,12 @@ struct inode * ext2_new_inode (const struct inode * dir, int mode) ...@@ -374,12 +367,12 @@ struct inode * ext2_new_inode (const struct inode * dir, int mode)
*/ */
if (!gdp) { if (!gdp) {
for (j = 0; j < sb->u.ext2_sb.s_groups_count; j++) { for (j = 0; j < sb->u.ext2_sb.s_groups_count; j++) {
tmp = get_group_desc (sb, j); tmp = get_group_desc (sb, j, &bh2);
if (tmp->bg_free_inodes_count && if (tmp->bg_free_inodes_count &&
tmp->bg_free_inodes_count >= avefreei) { tmp->bg_free_inodes_count >= avefreei) {
if (!gdp || if (!gdp ||
(tmp->bg_free_inodes_count > (tmp->bg_free_blocks_count >
gdp->bg_free_inodes_count)) { gdp->bg_free_blocks_count)) {
i = j; i = j;
gdp = tmp; gdp = tmp;
} }
...@@ -388,18 +381,25 @@ struct inode * ext2_new_inode (const struct inode * dir, int mode) ...@@ -388,18 +381,25 @@ struct inode * ext2_new_inode (const struct inode * dir, int mode)
} }
} }
else else
{ /* Try to place the inode in it\'s parent directory */ {
/*
* Try to place the inode in it's parent directory
*/
i = dir->u.ext2_i.i_block_group; i = dir->u.ext2_i.i_block_group;
tmp = get_group_desc (sb, i); tmp = get_group_desc (sb, i, &bh2);
if (tmp->bg_free_inodes_count) if (tmp->bg_free_inodes_count)
gdp = tmp; gdp = tmp;
else else
{ /* Use a quadratic hash to find a group with a free inode */ {
/*
* Use a quadratic hash to find a group with a
* free inode
*/
for (j = 1; j < sb->u.ext2_sb.s_groups_count; j <<= 1) { for (j = 1; j < sb->u.ext2_sb.s_groups_count; j <<= 1) {
i += j; i += j;
if (i >= sb->u.ext2_sb.s_groups_count) if (i >= sb->u.ext2_sb.s_groups_count)
i -= sb->u.ext2_sb.s_groups_count; i -= sb->u.ext2_sb.s_groups_count;
tmp = get_group_desc (sb, i); tmp = get_group_desc (sb, i, &bh2);
if (tmp->bg_free_inodes_count) { if (tmp->bg_free_inodes_count) {
gdp = tmp; gdp = tmp;
break; break;
...@@ -407,12 +407,14 @@ struct inode * ext2_new_inode (const struct inode * dir, int mode) ...@@ -407,12 +407,14 @@ struct inode * ext2_new_inode (const struct inode * dir, int mode)
} }
} }
if (!gdp) { if (!gdp) {
/* That failed: try linear search for a free inode */ /*
* That failed: try linear search for a free inode
*/
i = dir->u.ext2_i.i_block_group + 2; i = dir->u.ext2_i.i_block_group + 2;
for (j = 2; j < sb->u.ext2_sb.s_groups_count; j++) { for (j = 2; j < sb->u.ext2_sb.s_groups_count; j++) {
if (++i >= sb->u.ext2_sb.s_groups_count) if (++i >= sb->u.ext2_sb.s_groups_count)
i = 0; i = 0;
tmp = get_group_desc (sb,i); tmp = get_group_desc (sb, i, &bh2);
if (tmp->bg_free_inodes_count) { if (tmp->bg_free_inodes_count) {
gdp = tmp; gdp = tmp;
break; break;
...@@ -428,9 +430,6 @@ struct inode * ext2_new_inode (const struct inode * dir, int mode) ...@@ -428,9 +430,6 @@ struct inode * ext2_new_inode (const struct inode * dir, int mode)
} }
bitmap_nr = load_inode_bitmap (sb, i); bitmap_nr = load_inode_bitmap (sb, i);
bh = sb->u.ext2_sb.s_inode_bitmap[bitmap_nr]; bh = sb->u.ext2_sb.s_inode_bitmap[bitmap_nr];
if (!bh)
ext2_panic (sb, "ext2_new_inode",
"Unable to load bitmap for group %d", i);
if ((j = find_first_zero_bit ((unsigned long *) bh->b_data, if ((j = find_first_zero_bit ((unsigned long *) bh->b_data,
EXT2_INODES_PER_GROUP(sb))) < EXT2_INODES_PER_GROUP(sb))) <
EXT2_INODES_PER_GROUP(sb)) { EXT2_INODES_PER_GROUP(sb)) {
...@@ -447,9 +446,9 @@ struct inode * ext2_new_inode (const struct inode * dir, int mode) ...@@ -447,9 +446,9 @@ struct inode * ext2_new_inode (const struct inode * dir, int mode)
} else } else
goto repeat; goto repeat;
j += i * EXT2_INODES_PER_GROUP(sb) + 1; j += i * EXT2_INODES_PER_GROUP(sb) + 1;
if (j > es->s_inodes_count) { if (j < EXT2_FIRST_INO || j > es->s_inodes_count) {
ext2_error (sb, "ext2_new_inode", ext2_error (sb, "ext2_new_inode",
"inode > inodes count\n" "reserved inode or inode > inodes count\n"
"block_group = %d,inode=%d", i, j); "block_group = %d,inode=%d", i, j);
unlock_super (sb); unlock_super (sb);
iput (inode); iput (inode);
...@@ -458,7 +457,7 @@ struct inode * ext2_new_inode (const struct inode * dir, int mode) ...@@ -458,7 +457,7 @@ struct inode * ext2_new_inode (const struct inode * dir, int mode)
gdp->bg_free_inodes_count--; gdp->bg_free_inodes_count--;
if (S_ISDIR(mode)) if (S_ISDIR(mode))
gdp->bg_used_dirs_count++; gdp->bg_used_dirs_count++;
sb->u.ext2_sb.s_group_desc[i / EXT2_DESC_PER_BLOCK(sb)]->b_dirt = 1; bh2->b_dirt = 1;
es->s_free_inodes_count--; es->s_free_inodes_count--;
sb->u.ext2_sb.s_sbh->b_dirt = 1; sb->u.ext2_sb.s_sbh->b_dirt = 1;
sb->s_dirt = 1; sb->s_dirt = 1;
...@@ -468,7 +467,10 @@ struct inode * ext2_new_inode (const struct inode * dir, int mode) ...@@ -468,7 +467,10 @@ struct inode * ext2_new_inode (const struct inode * dir, int mode)
inode->i_nlink = 1; inode->i_nlink = 1;
inode->i_dev = sb->s_dev; inode->i_dev = sb->s_dev;
inode->i_uid = current->euid; inode->i_uid = current->euid;
inode->i_gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->egid; if ((dir->i_mode & S_ISGID) || test_opt (sb, GRPID))
inode->i_gid = dir->i_gid;
else
inode->i_gid = current->egid;
inode->i_dirt = 1; inode->i_dirt = 1;
inode->i_ino = j; inode->i_ino = j;
inode->i_blksize = sb->s_blocksize; inode->i_blksize = sb->s_blocksize;
...@@ -499,8 +501,6 @@ unsigned long ext2_count_free_inodes (struct super_block * sb) ...@@ -499,8 +501,6 @@ unsigned long ext2_count_free_inodes (struct super_block * sb)
#ifdef EXT2FS_DEBUG #ifdef EXT2FS_DEBUG
struct ext2_super_block * es; struct ext2_super_block * es;
unsigned long desc_count, bitmap_count, x; unsigned long desc_count, bitmap_count, x;
unsigned long group_desc;
unsigned long desc;
int bitmap_nr; int bitmap_nr;
struct ext2_group_desc * gdp; struct ext2_group_desc * gdp;
int i; int i;
...@@ -509,36 +509,16 @@ unsigned long ext2_count_free_inodes (struct super_block * sb) ...@@ -509,36 +509,16 @@ unsigned long ext2_count_free_inodes (struct super_block * sb)
es = sb->u.ext2_sb.s_es; es = sb->u.ext2_sb.s_es;
desc_count = 0; desc_count = 0;
bitmap_count = 0; bitmap_count = 0;
group_desc = 0;
desc = 0;
gdp = NULL; gdp = NULL;
for (i = 0; i < sb->u.ext2_sb.s_groups_count; i++) { for (i = 0; i < sb->u.ext2_sb.s_groups_count; i++) {
if (!gdp) { gdp = get_group_desc (sb, i, NULL);
if (!sb->u.ext2_sb.s_group_desc[group_desc]) { desc_count += gdp->bg_free_inodes_count;
printk ("ext2_count_free_inodes: Descriptor not loaded\n");
break;
}
gdp = (struct ext2_group_desc *) sb->u.ext2_sb.s_group_desc[group_desc]->b_data;
}
desc_count += gdp[desc].bg_free_inodes_count;
bitmap_nr = load_inode_bitmap (sb, i); bitmap_nr = load_inode_bitmap (sb, i);
if (sb->u.ext2_sb.s_inode_bitmap[bitmap_nr])
x = ext2_count_free (sb->u.ext2_sb.s_inode_bitmap[bitmap_nr], x = ext2_count_free (sb->u.ext2_sb.s_inode_bitmap[bitmap_nr],
EXT2_INODES_PER_GROUP(sb) / 8); EXT2_INODES_PER_GROUP(sb) / 8);
else {
x = 0;
printk ("Cannot load inode bitmap for group %d (bitmap = %d)\n",
i, bitmap_nr);
}
printk ("group %d: stored = %d, counted = %lu\n", printk ("group %d: stored = %d, counted = %lu\n",
i, gdp[desc].bg_free_inodes_count, x); i, gdp->bg_free_inodes_count, x);
bitmap_count += x; bitmap_count += x;
desc++;
if (desc == EXT2_DESC_PER_BLOCK(sb)) {
group_desc++;
desc = 0;
gdp = NULL;
}
} }
printk("ext2_count_free_inodes: stored = %lu, computed = %lu, %lu\n", printk("ext2_count_free_inodes: stored = %lu, computed = %lu, %lu\n",
es->s_free_inodes_count, desc_count, bitmap_count); es->s_free_inodes_count, desc_count, bitmap_count);
...@@ -553,8 +533,6 @@ void ext2_check_inodes_bitmap (struct super_block * sb) ...@@ -553,8 +533,6 @@ void ext2_check_inodes_bitmap (struct super_block * sb)
{ {
struct ext2_super_block * es; struct ext2_super_block * es;
unsigned long desc_count, bitmap_count, x; unsigned long desc_count, bitmap_count, x;
unsigned long group_desc;
unsigned long desc;
int bitmap_nr; int bitmap_nr;
struct ext2_group_desc * gdp; struct ext2_group_desc * gdp;
int i; int i;
...@@ -563,42 +541,19 @@ void ext2_check_inodes_bitmap (struct super_block * sb) ...@@ -563,42 +541,19 @@ void ext2_check_inodes_bitmap (struct super_block * sb)
es = sb->u.ext2_sb.s_es; es = sb->u.ext2_sb.s_es;
desc_count = 0; desc_count = 0;
bitmap_count = 0; bitmap_count = 0;
group_desc = 0;
desc = 0;
gdp = NULL; gdp = NULL;
for (i = 0; i < sb->u.ext2_sb.s_groups_count; i++) { for (i = 0; i < sb->u.ext2_sb.s_groups_count; i++) {
if (!gdp) { gdp = get_group_desc (sb, i, NULL);
if (!sb->u.ext2_sb.s_group_desc[group_desc]) { desc_count += gdp->bg_free_inodes_count;
ext2_error (sb, "ext2_check_inodes_bitmap",
"Descriptor not loaded for group %d",
i);
break;
}
gdp = (struct ext2_group_desc *) sb->u.ext2_sb.s_group_desc[group_desc]->b_data;
}
desc_count += gdp[desc].bg_free_inodes_count;
bitmap_nr = load_inode_bitmap (sb, i); bitmap_nr = load_inode_bitmap (sb, i);
if (sb->u.ext2_sb.s_inode_bitmap[bitmap_nr])
x = ext2_count_free (sb->u.ext2_sb.s_inode_bitmap[bitmap_nr], x = ext2_count_free (sb->u.ext2_sb.s_inode_bitmap[bitmap_nr],
EXT2_INODES_PER_GROUP(sb) / 8); EXT2_INODES_PER_GROUP(sb) / 8);
else { if (gdp->bg_free_inodes_count != x)
x = 0;
ext2_error (sb, "ext2_check_inodes_bitmap",
"Cannot load bitmap for group %d (bitmap = %d)",
i, bitmap_nr);
}
if (gdp[desc].bg_free_inodes_count != x)
ext2_error (sb, "ext2_check_inodes_bitmap", ext2_error (sb, "ext2_check_inodes_bitmap",
"Wrong free inodes count in group %d, " "Wrong free inodes count in group %d, "
"stored = %d, counted = %lu", i, "stored = %d, counted = %lu", i,
gdp[desc].bg_free_inodes_count, x); gdp->bg_free_inodes_count, x);
bitmap_count += x; bitmap_count += x;
desc++;
if (desc == EXT2_DESC_PER_BLOCK(sb)) {
group_desc++;
desc = 0;
gdp = NULL;
}
} }
if (es->s_free_inodes_count != bitmap_count) if (es->s_free_inodes_count != bitmap_count)
ext2_error (sb, "ext2_check_inodes_bitmap", ext2_error (sb, "ext2_check_inodes_bitmap",
......
/* /*
* linux/fs/ext2/inode.c * linux/fs/ext2/inode.c
* *
* Copyright (C) 1992, 1993 Remy Card (card@masi.ibp.fr) * Copyright (C) 1992, 1993, 1994 Remy Card (card@masi.ibp.fr)
* Laboratoire MASI - Institut Blaise Pascal
* Universite Pierre et Marie Curie (Paris VI)
* *
* from * from
* *
...@@ -18,14 +20,22 @@ ...@@ -18,14 +20,22 @@
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/ext2_fs.h> #include <linux/ext2_fs.h>
#include <linux/kernel.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/stat.h> #include <linux/stat.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/locks.h> #include <linux/locks.h>
#define clear_block(addr,size) \
__asm__("cld\n\t" \
"rep\n\t" \
"stosl" \
: \
:"a" (0), "c" (size / 4), "D" ((long) (addr)) \
:"cx", "di")
void ext2_put_inode (struct inode * inode) void ext2_put_inode (struct inode * inode)
{ {
ext2_discard_prealloc (inode);
if (inode->i_nlink || inode->i_ino == EXT2_ACL_IDX_INO || if (inode->i_nlink || inode->i_ino == EXT2_ACL_IDX_INO ||
inode->i_ino == EXT2_ACL_DATA_INO) inode->i_ino == EXT2_ACL_DATA_INO)
return; return;
...@@ -48,6 +58,78 @@ static int block_bmap (struct buffer_head * bh, int nr) ...@@ -48,6 +58,78 @@ static int block_bmap (struct buffer_head * bh, int nr)
return tmp; return tmp;
} }
/*
* ext2_discard_prealloc and ext2_alloc_block are atomic wrt. the
* superblock in the same manner as are ext2_free_blocks and
* ext2_new_block. We just wait on the super rather than locking it
* here, since ext2_new_block will do the necessary locking and we
* can't block until then.
*/
void ext2_discard_prealloc (struct inode * inode)
{
#ifdef EXT2_PREALLOCATE
if (inode->u.ext2_i.i_prealloc_count) {
ext2_free_blocks (inode->i_sb,
inode->u.ext2_i.i_prealloc_block,
inode->u.ext2_i.i_prealloc_count);
inode->u.ext2_i.i_prealloc_count = 0;
}
#endif
}
static int ext2_alloc_block (struct inode * inode, unsigned long goal)
{
#ifdef EXT2FS_DEBUG
static unsigned long alloc_hits = 0, alloc_attempts = 0;
#endif
unsigned long result;
struct buffer_head * bh;
wait_on_super (inode->i_sb);
#ifdef EXT2_PREALLOCATE
if (inode->u.ext2_i.i_prealloc_count &&
(goal == inode->u.ext2_i.i_prealloc_block ||
goal + 1 == inode->u.ext2_i.i_prealloc_block))
{
result = inode->u.ext2_i.i_prealloc_block++;
inode->u.ext2_i.i_prealloc_count--;
ext2_debug ("preallocation hit (%lu/%lu).\n",
++alloc_hits, ++alloc_attempts);
/* It doesn't matter if we block in getblk() since
we have already atomically allocated the block, and
are only clearing it now. */
if (!(bh = getblk (inode->i_sb->s_dev, result,
inode->i_sb->s_blocksize))) {
ext2_error (inode->i_sb, "ext2_alloc_block",
"cannot get block %lu", result);
return 0;
}
clear_block (bh->b_data, inode->i_sb->s_blocksize);
bh->b_uptodate = 1;
bh->b_dirt = 1;
brelse (bh);
} else {
ext2_discard_prealloc (inode);
ext2_debug ("preallocation miss (%lu/%lu).\n",
alloc_hits, ++alloc_attempts);
if (S_ISREG(inode->i_mode))
result = ext2_new_block
(inode->i_sb, goal,
&inode->u.ext2_i.i_prealloc_count,
&inode->u.ext2_i.i_prealloc_block);
else
result = ext2_new_block (inode->i_sb, goal, 0, 0);
}
#else
result = ext2_new_block (inode->i_sb, goal, 0, 0);
#endif
return result;
}
int ext2_bmap (struct inode * inode, int block) int ext2_bmap (struct inode * inode, int block)
{ {
int i; int i;
...@@ -147,12 +229,12 @@ static struct buffer_head * inode_getblk (struct inode * inode, int nr, ...@@ -147,12 +229,12 @@ static struct buffer_head * inode_getblk (struct inode * inode, int nr,
ext2_debug ("goal = %d.\n", goal); ext2_debug ("goal = %d.\n", goal);
tmp = ext2_new_block (inode->i_sb, goal); tmp = ext2_alloc_block (inode, goal);
if (!tmp) if (!tmp)
return NULL; return NULL;
result = getblk (inode->i_dev, tmp, inode->i_sb->s_blocksize); result = getblk (inode->i_dev, tmp, inode->i_sb->s_blocksize);
if (*p) { if (*p) {
ext2_free_block (inode->i_sb, tmp); ext2_free_blocks (inode->i_sb, tmp, 1);
brelse (result); brelse (result);
goto repeat; goto repeat;
} }
...@@ -219,14 +301,14 @@ static struct buffer_head * block_getblk (struct inode * inode, ...@@ -219,14 +301,14 @@ static struct buffer_head * block_getblk (struct inode * inode,
if (!goal) if (!goal)
goal = bh->b_blocknr + 1; goal = bh->b_blocknr + 1;
} }
tmp = ext2_new_block (inode->i_sb, goal); tmp = ext2_alloc_block (inode, goal);
if (!tmp) { if (!tmp) {
brelse (bh); brelse (bh);
return NULL; return NULL;
} }
result = getblk (bh->b_dev, tmp, blocksize); result = getblk (bh->b_dev, tmp, blocksize);
if (*p) { if (*p) {
ext2_free_block (inode->i_sb, tmp); ext2_free_blocks (inode->i_sb, tmp, 1);
brelse (result); brelse (result);
goto repeat; goto repeat;
} }
...@@ -263,9 +345,11 @@ struct buffer_head * ext2_getblk (struct inode * inode, long block, ...@@ -263,9 +345,11 @@ struct buffer_head * ext2_getblk (struct inode * inode, long block,
ext2_warning (inode->i_sb, "ext2_getblk", "block > big"); ext2_warning (inode->i_sb, "ext2_getblk", "block > big");
return NULL; return NULL;
} }
/* If this is a sequential block allocation, set the next_alloc_block /*
to this block now so that all the indblock and data block * If this is a sequential block allocation, set the next_alloc_block
allocations use the same goal zone */ * to this block now so that all the indblock and data block
* allocations use the same goal zone
*/
ext2_debug ("block %lu, next %lu, goal %lu.\n", block, ext2_debug ("block %lu, next %lu, goal %lu.\n", block,
inode->u.ext2_i.i_next_alloc_block, inode->u.ext2_i.i_next_alloc_block,
...@@ -379,6 +463,9 @@ void ext2_read_inode (struct inode * inode) ...@@ -379,6 +463,9 @@ void ext2_read_inode (struct inode * inode)
inode->u.ext2_i.i_block_group = block_group; inode->u.ext2_i.i_block_group = block_group;
inode->u.ext2_i.i_next_alloc_block = 0; inode->u.ext2_i.i_next_alloc_block = 0;
inode->u.ext2_i.i_next_alloc_goal = 0; inode->u.ext2_i.i_next_alloc_goal = 0;
if (inode->u.ext2_i.i_prealloc_count)
ext2_error (inode->i_sb, "ext2_read_inode",
"New inode has non-zero prealloc count!");
if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
inode->i_rdev = raw_inode->i_block[0]; inode->i_rdev = raw_inode->i_block[0];
else for (block = 0; block < EXT2_N_BLOCKS; block++) else for (block = 0; block < EXT2_N_BLOCKS; block++)
......
/* /*
* linux/fs/ext2/ioctl.c * linux/fs/ext2/ioctl.c
* *
* Copyright (C) 1993 Remy Card (card@masi.ibp.fr) * Copyright (C) 1993, 1994 Remy Card (card@masi.ibp.fr)
* Laboratoire MASI - Institut Blaise Pascal
* Universite Pierre et Marie Curie (Paris VI)
*/ */
#include <asm/segment.h> #include <asm/segment.h>
......
/* /*
* linux/fs/ext2/namei.c * linux/fs/ext2/namei.c
* *
* Copyright (C) 1992, 1993 Remy Card (card@masi.ibp.fr) * Copyright (C) 1992, 1993, 1994 Remy Card (card@masi.ibp.fr)
* Laboratoire MASI - Institut Blaise Pascal
* Universite Pierre et Marie Curie (Paris VI)
* *
* from * from
* *
...@@ -16,7 +18,6 @@ ...@@ -16,7 +18,6 @@
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/ext2_fs.h> #include <linux/ext2_fs.h>
#include <linux/fcntl.h> #include <linux/fcntl.h>
#include <linux/kernel.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/stat.h> #include <linux/stat.h>
#include <linux/string.h> #include <linux/string.h>
...@@ -28,6 +29,14 @@ ...@@ -28,6 +29,14 @@
*/ */
/* #define NO_TRUNCATE */ /* #define NO_TRUNCATE */
/*
* define how far ahead to read directories while searching them.
*/
#define NAMEI_RA_CHUNKS 2
#define NAMEI_RA_BLOCKS 4
#define NAMEI_RA_SIZE (NAMEI_RA_CHUNKS * NAMEI_RA_BLOCKS)
#define NAMEI_RA_INDEX(c,b) (((c) * NAMEI_RA_BLOCKS) + (b))
/* /*
* NOTE! unlike strncmp, ext2_match returns 1 for success, 0 for failure. * NOTE! unlike strncmp, ext2_match returns 1 for success, 0 for failure.
*/ */
...@@ -38,7 +47,9 @@ static int ext2_match (int len, const char * const name, ...@@ -38,7 +47,9 @@ static int ext2_match (int len, const char * const name,
if (!de || !de->inode || len > EXT2_NAME_LEN) if (!de || !de->inode || len > EXT2_NAME_LEN)
return 0; return 0;
/* "" means "." ---> so paths like "/usr/lib//libc.a" work */ /*
* "" means "." ---> so paths like "/usr/lib//libc.a" work
*/
if (!len && de->name_len == 1 && (de->name[0] == '.') && if (!len && de->name_len == 1 && (de->name[0] == '.') &&
(de->name[1] == '\0')) (de->name[1] == '\0'))
return 1; return 1;
...@@ -60,22 +71,22 @@ static int ext2_match (int len, const char * const name, ...@@ -60,22 +71,22 @@ static int ext2_match (int len, const char * const name,
* returns the cache buffer in which the entry was found, and the entry * returns the cache buffer in which the entry was found, and the entry
* itself (as a parameter - res_dir). It does NOT read the inode of the * itself (as a parameter - res_dir). It does NOT read the inode of the
* entry - you'll have to do that yourself if you want to. * entry - you'll have to do that yourself if you want to.
*
*/ */
static struct buffer_head * ext2_find_entry (struct inode * dir, static struct buffer_head * ext2_find_entry (struct inode * dir,
const char * const name, int namelen, const char * const name, int namelen,
struct ext2_dir_entry ** res_dir) struct ext2_dir_entry ** res_dir)
{ {
unsigned long offset;
struct buffer_head * bh;
struct ext2_dir_entry * de;
struct super_block * sb; struct super_block * sb;
int err; struct buffer_head * bh_use[NAMEI_RA_SIZE];
struct buffer_head * bh_read[NAMEI_RA_SIZE];
unsigned long offset;
int block, toread, i, err;
*res_dir = NULL; *res_dir = NULL;
if (!dir) if (!dir)
return NULL; return NULL;
sb = dir->i_sb; sb = dir->i_sb;
#ifdef NO_TRUNCATE #ifdef NO_TRUNCATE
if (namelen > EXT2_NAME_LEN) if (namelen > EXT2_NAME_LEN)
return NULL; return NULL;
...@@ -83,34 +94,76 @@ static struct buffer_head * ext2_find_entry (struct inode * dir, ...@@ -83,34 +94,76 @@ static struct buffer_head * ext2_find_entry (struct inode * dir,
if (namelen > EXT2_NAME_LEN) if (namelen > EXT2_NAME_LEN)
namelen = EXT2_NAME_LEN; namelen = EXT2_NAME_LEN;
#endif #endif
bh = ext2_bread (dir, 0, 0, &err);
if (!bh) memset (bh_use, 0, sizeof (bh_use));
return NULL; toread = 0;
for (block = 0; block < NAMEI_RA_SIZE; ++block) {
struct buffer_head * bh;
if ((block << EXT2_BLOCK_SIZE_BITS (sb)) >= dir->i_size)
break;
bh = ext2_getblk (dir, block, 0, &err);
bh_use[block] = bh;
if (bh && !bh->b_uptodate)
bh_read[toread++] = bh;
}
block = 0;
offset = 0; offset = 0;
de = (struct ext2_dir_entry *) bh->b_data;
while (offset < dir->i_size) { while (offset < dir->i_size) {
if (!bh || (char *)de >= sb->s_blocksize + bh->b_data) { struct buffer_head * bh;
brelse (bh); struct ext2_dir_entry * de;
bh = ext2_bread (dir, offset >> EXT2_BLOCK_SIZE_BITS(sb), 0, &err); char * dlimit;
if (!bh) {
offset += sb->s_blocksize; if ((block % NAMEI_RA_BLOCKS) == 0 && toread) {
continue; ll_rw_block (READ, toread, bh_read);
} toread = 0;
de = (struct ext2_dir_entry *) bh->b_data;
} }
if (! ext2_check_dir_entry ("ext2_find_entry", dir, de, bh, bh = bh_use[block % NAMEI_RA_SIZE];
offset)) { if (!bh)
brelse (bh); ext2_panic (sb, "ext2_find_entry",
return NULL; "buffer head pointer is NULL");
wait_on_buffer (bh);
if (!bh->b_uptodate) {
/*
* read error: all bets are off
*/
break;
} }
de = (struct ext2_dir_entry *) bh->b_data;
dlimit = bh->b_data + sb->s_blocksize;
while ((char *) de < dlimit) {
if (!ext2_check_dir_entry ("ext2_find_entry", dir,
de, bh, offset))
goto failure;
if (de->inode != 0 && ext2_match (namelen, name, de)) { if (de->inode != 0 && ext2_match (namelen, name, de)) {
for (i = 0; i < NAMEI_RA_SIZE; ++i) {
if (bh_use[i] != bh)
brelse (bh_use[i]);
}
*res_dir = de; *res_dir = de;
return bh; return bh;
} }
offset += de->rec_len; offset += de->rec_len;
de = (struct ext2_dir_entry *) ((char *) de + de->rec_len); de = (struct ext2_dir_entry *)
((char *) de + de->rec_len);
} }
brelse (bh); brelse (bh);
if (((block + NAMEI_RA_SIZE) << EXT2_BLOCK_SIZE_BITS (sb)) >=
dir->i_size)
bh = NULL;
else
bh = ext2_getblk (dir, block + NAMEI_RA_SIZE, 0, &err);
bh_use[block++ % NAMEI_RA_SIZE] = bh;
if (bh && !bh->b_uptodate)
bh_read[toread++] = bh;
}
failure:
for (i = 0; i < NAMEI_RA_SIZE; ++i)
brelse (bh_use[i]);
return NULL; return NULL;
} }
...@@ -187,8 +240,9 @@ static struct buffer_head * ext2_add_entry (struct inode * dir, ...@@ -187,8 +240,9 @@ static struct buffer_head * ext2_add_entry (struct inode * dir,
#endif #endif
if (!namelen) if (!namelen)
return NULL; return NULL;
/* Is this a busy deleted directory? Can't create new files /*
if so */ * Is this a busy deleted directory? Can't create new files if so
*/
if (dir->i_size == 0) if (dir->i_size == 0)
{ {
*err = -ENOENT; *err = -ENOENT;
...@@ -231,7 +285,7 @@ static struct buffer_head * ext2_add_entry (struct inode * dir, ...@@ -231,7 +285,7 @@ static struct buffer_head * ext2_add_entry (struct inode * dir,
de = (struct ext2_dir_entry *) bh->b_data; de = (struct ext2_dir_entry *) bh->b_data;
} }
} }
if (! ext2_check_dir_entry ("ext2_add_entry", dir, de, bh, if (!ext2_check_dir_entry ("ext2_add_entry", dir, de, bh,
offset)) { offset)) {
*err = -ENOENT; *err = -ENOENT;
brelse (bh); brelse (bh);
...@@ -295,13 +349,12 @@ static int ext2_delete_entry (struct ext2_dir_entry * dir, ...@@ -295,13 +349,12 @@ static int ext2_delete_entry (struct ext2_dir_entry * dir,
pde = NULL; pde = NULL;
de = (struct ext2_dir_entry *) bh->b_data; de = (struct ext2_dir_entry *) bh->b_data;
while (i < bh->b_size) { while (i < bh->b_size) {
if (! ext2_check_dir_entry ("ext2_delete_entry", NULL, if (!ext2_check_dir_entry ("ext2_delete_entry", NULL,
de, bh, i)) de, bh, i))
return -EIO; return -EIO;
if (de == dir) { if (de == dir) {
if (pde) if (pde)
pde->rec_len += dir->rec_len; pde->rec_len += dir->rec_len;
/* XXX - must zero the inode number in every case !! */
dir->inode = 0; dir->inode = 0;
return 0; return 0;
} }
...@@ -548,7 +601,7 @@ static int empty_dir (struct inode * inode) ...@@ -548,7 +601,7 @@ static int empty_dir (struct inode * inode)
} }
de = (struct ext2_dir_entry *) bh->b_data; de = (struct ext2_dir_entry *) bh->b_data;
} }
if (! ext2_check_dir_entry ("empty_dir", inode, de, bh, if (!ext2_check_dir_entry ("empty_dir", inode, de, bh,
offset)) { offset)) {
brelse (bh); brelse (bh);
return 1; return 1;
...@@ -609,10 +662,13 @@ int ext2_rmdir (struct inode * dir, const char * name, int len) ...@@ -609,10 +662,13 @@ int ext2_rmdir (struct inode * dir, const char * name, int len)
goto end_rmdir; goto end_rmdir;
} }
if (inode->i_count > 1) { if (inode->i_count > 1) {
/* Are we deleting the last instance of a busy directory? /*
Better clean up if so. */ * Are we deleting the last instance of a busy directory?
/* Make directory empty (it will be truncated when finally * Better clean up if so.
dereferenced). This also inhibits ext2_add_entry. */ *
* Make directory empty (it will be truncated when finally
* dereferenced). This also inhibits ext2_add_entry.
*/
inode->i_size = 0; inode->i_size = 0;
} }
retval = ext2_delete_entry (de, bh); retval = ext2_delete_entry (de, bh);
...@@ -969,14 +1025,18 @@ static int do_ext2_rename (struct inode * old_dir, const char * old_name, ...@@ -969,14 +1025,18 @@ static int do_ext2_rename (struct inode * old_dir, const char * old_name,
&retval); &retval);
if (!new_bh) if (!new_bh)
goto end_rename; goto end_rename;
/* sanity checking before doing the rename - avoid races */ /*
* sanity checking before doing the rename - avoid races
*/
if (new_inode && (new_de->inode != new_inode->i_ino)) if (new_inode && (new_de->inode != new_inode->i_ino))
goto try_again; goto try_again;
if (new_de->inode && !new_inode) if (new_de->inode && !new_inode)
goto try_again; goto try_again;
if (old_de->inode != old_inode->i_ino) if (old_de->inode != old_inode->i_ino)
goto try_again; goto try_again;
/* ok, that's it */ /*
* ok, that's it
*/
new_de->inode = old_inode->i_ino; new_de->inode = old_inode->i_ino;
#ifndef DONT_USE_DCACHE #ifndef DONT_USE_DCACHE
ext2_dcache_remove (old_dir->i_dev, old_dir->i_ino, old_de->name, ext2_dcache_remove (old_dir->i_dev, old_dir->i_ino, old_de->name,
......
/* /*
* linux/fs/ext2/super.c * linux/fs/ext2/super.c
* *
* Copyright (C) 1992, 1993 Remy Card (card@masi.ibp.fr) * Copyright (C) 1992, 1993, 1994 Remy Card (card@masi.ibp.fr)
* Laboratoire MASI - Institut Blaise Pascal
* Universite Pierre et Marie Curie (Paris VI)
* *
* from * from
* *
...@@ -18,7 +20,6 @@ ...@@ -18,7 +20,6 @@
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/ext2_fs.h> #include <linux/ext2_fs.h>
#include <linux/kernel.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/stat.h> #include <linux/stat.h>
#include <linux/string.h> #include <linux/string.h>
...@@ -41,15 +42,22 @@ void ext2_error (struct super_block * sb, const char * function, ...@@ -41,15 +42,22 @@ void ext2_error (struct super_block * sb, const char * function,
va_start (args, fmt); va_start (args, fmt);
vsprintf (buf, fmt, args); vsprintf (buf, fmt, args);
va_end (args); va_end (args);
printk ( if (test_opt (sb, ERRORS_PANIC) ||
#ifdef KERN_ERR (sb->u.ext2_sb.s_es->s_errors == EXT2_ERRORS_PANIC &&
KERN_ERR !test_opt (sb, ERRORS_CONT) && !test_opt (sb, ERRORS_RO)))
#endif panic ("EXT2-fs panic (device %d/%d): %s: %s\n",
"EXT2-fs error (device %d/%d): %s: %s\n", MAJOR(sb->s_dev), MINOR(sb->s_dev), function, buf);
printk (KERN_CRIT "EXT2-fs error (device %d/%d): %s: %s\n",
MAJOR(sb->s_dev), MINOR(sb->s_dev), function, buf); MAJOR(sb->s_dev), MINOR(sb->s_dev), function, buf);
if (test_opt (sb, ERRORS_RO) ||
(sb->u.ext2_sb.s_es->s_errors == EXT2_ERRORS_RO &&
!test_opt (sb, ERRORS_CONT) && !test_opt (sb, ERRORS_PANIC))) {
printk ("Remounting filesystem read-only\n");
sb->s_flags |= MS_RDONLY;
}
} }
volatile void ext2_panic (struct super_block * sb, const char * function, NORET_TYPE void ext2_panic (struct super_block * sb, const char * function,
const char * fmt, ...) const char * fmt, ...)
{ {
char buf[1024]; char buf[1024];
...@@ -77,11 +85,7 @@ void ext2_warning (struct super_block * sb, const char * function, ...@@ -77,11 +85,7 @@ void ext2_warning (struct super_block * sb, const char * function,
va_start (args, fmt); va_start (args, fmt);
vsprintf (buf, fmt, args); vsprintf (buf, fmt, args);
va_end (args); va_end (args);
printk ( printk (KERN_WARNING "EXT2-fs warning (device %d/%d): %s: %s\n",
#ifdef KERN_WARNING
KERN_WARNING
#endif
"EXT2-fs warning (device %d/%d): %s: %s\n",
MAJOR(sb->s_dev), MINOR(sb->s_dev), function, buf); MAJOR(sb->s_dev), MINOR(sb->s_dev), function, buf);
} }
...@@ -181,15 +185,75 @@ static int parse_options (char * options, unsigned long * sb_block, ...@@ -181,15 +185,75 @@ static int parse_options (char * options, unsigned long * sb_block,
this_char = strtok (NULL, ",")) { this_char = strtok (NULL, ",")) {
if ((value = strchr (this_char, '=')) != NULL) if ((value = strchr (this_char, '=')) != NULL)
*value++ = 0; *value++ = 0;
if (!strcmp (this_char, "check")) if (!strcmp (this_char, "check")) {
*mount_options |= EXT2_MOUNT_CHECK;
else if (!strcmp (this_char, "sb")) {
if (!value || !*value) if (!value || !*value)
set_opt (*mount_options, CHECK_NORMAL);
else if (!strcmp (value, "none")) {
clear_opt (*mount_options, CHECK_NORMAL);
clear_opt (*mount_options, CHECK_STRICT);
}
else if (strcmp (value, "normal"))
set_opt (*mount_options, CHECK_NORMAL);
else if (strcmp (value, "strict")) {
set_opt (*mount_options, CHECK_NORMAL);
set_opt (*mount_options, CHECK_STRICT);
}
else {
printk ("EXT2-fs: Invalid check option: %s\n",
value);
return 0; return 0;
}
}
else if (!strcmp (this_char, "debug"))
set_opt (*mount_options, DEBUG);
else if (!strcmp (this_char, "errors")) {
if (!value || !*value) {
printk ("EXT2-fs: the errors option requires "
"an argument");
return 0;
}
if (!strcmp (value, "continue")) {
clear_opt (*mount_options, ERRORS_RO);
clear_opt (*mount_options, ERRORS_PANIC);
set_opt (*mount_options, ERRORS_CONT);
}
else if (!strcmp (value, "remount-ro")) {
clear_opt (*mount_options, ERRORS_CONT);
clear_opt (*mount_options, ERRORS_PANIC);
set_opt (*mount_options, ERRORS_RO);
}
else if (!strcmp (value, "panic")) {
clear_opt (*mount_options, ERRORS_CONT);
clear_opt (*mount_options, ERRORS_RO);
set_opt (*mount_options, ERRORS_PANIC);
}
else {
printk ("EXT2-fs: Invalid errors option: %s\n",
value);
return 0;
}
}
else if (!strcmp (this_char, "grpid"))
set_opt (*mount_options, GRPID);
else if (!strcmp (this_char, "nocheck")) {
clear_opt (*mount_options, CHECK_NORMAL);
clear_opt (*mount_options, CHECK_STRICT);
}
else if (!strcmp (this_char, "nogrpid"))
clear_opt (*mount_options, GRPID);
else if (!strcmp (this_char, "sb")) {
if (!value || !*value) {
printk ("EXT2-fs: the sb option requires "
"an argument");
return 0;
}
*sb_block = simple_strtoul (value, &value, 0); *sb_block = simple_strtoul (value, &value, 0);
if (*value) if (*value) {
printk ("EXT2-fs: Invalid sb option: %s\n",
value);
return 0; return 0;
} }
}
else { else {
printk ("EXT2-fs: Unrecognized mount option %s\n", this_char); printk ("EXT2-fs: Unrecognized mount option %s\n", this_char);
return 0; return 0;
...@@ -198,102 +262,191 @@ static int parse_options (char * options, unsigned long * sb_block, ...@@ -198,102 +262,191 @@ static int parse_options (char * options, unsigned long * sb_block,
return 1; return 1;
} }
struct super_block * ext2_read_super (struct super_block * s, void * data, static void ext2_setup_super (struct super_block * sb,
struct ext2_super_block * es)
{
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 (es->s_mnt_count >= es->s_max_mnt_count)
printk ("EXT2-fs warning: maximal mount count reached, "
"running e2fsck is recommended\n");
if (!(sb->s_flags & MS_RDONLY)) {
es->s_state &= ~EXT2_VALID_FS;
if (!es->s_max_mnt_count)
es->s_max_mnt_count = EXT2_DFL_MAX_MNT_COUNT;
es->s_mnt_count++;
es->s_mtime = CURRENT_TIME;
sb->u.ext2_sb.s_sbh->b_dirt = 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 (test_opt (sb, CHECK)) {
ext2_check_blocks_bitmap (sb);
ext2_check_inodes_bitmap (sb);
}
}
}
static int ext2_check_descriptors (struct super_block * sb)
{
int i;
int desc_block = 0;
unsigned long block = sb->u.ext2_sb.s_es->s_first_data_block;
struct ext2_group_desc * gdp = NULL;
ext2_debug ("Checking group descriptors");
for (i = 0; i < sb->u.ext2_sb.s_groups_count; i++)
{
if ((i % EXT2_DESC_PER_BLOCK(sb)) == 0)
gdp = (struct ext2_group_desc *) sb->u.ext2_sb.s_group_desc[desc_block++]->b_data;
if (gdp->bg_block_bitmap < block ||
gdp->bg_block_bitmap >= block + EXT2_BLOCKS_PER_GROUP(sb))
{
ext2_error (sb, "ext2_check_desciptors",
"Block bitmap for group %d"
" not in group (block %lu)!",
i, gdp->bg_block_bitmap);
return 0;
}
if (gdp->bg_inode_bitmap < block ||
gdp->bg_inode_bitmap >= block + EXT2_BLOCKS_PER_GROUP(sb))
{
ext2_error (sb, "ext2_check_desciptors",
"Inode bitmap for group %d"
" not in group (block %lu)!",
i, gdp->bg_inode_bitmap);
return 0;
}
if (gdp->bg_inode_table < block ||
gdp->bg_inode_table + sb->u.ext2_sb.s_itb_per_group >=
block + EXT2_BLOCKS_PER_GROUP(sb))
{
ext2_error (sb, "ext2_check_desciptors",
"Inode table for group %d"
" not in group (block %lu)!",
i, gdp->bg_inode_table);
return 0;
}
block += EXT2_BLOCKS_PER_GROUP(sb);
gdp++;
}
return 1;
}
struct super_block * ext2_read_super (struct super_block * sb, void * data,
int silent) int silent)
{ {
struct buffer_head * bh; struct buffer_head * bh;
struct ext2_super_block * es; struct ext2_super_block * es;
unsigned long sb_block = 1; unsigned long sb_block = 1;
unsigned long logic_sb_block = 1; unsigned long logic_sb_block = 1;
int dev = s->s_dev; int dev = sb->s_dev;
int bh_count; int bh_count;
int i, j; int i, j;
#ifdef EXT2FS_PRE_02B_COMPAT #ifdef EXT2FS_PRE_02B_COMPAT
int fs_converted = 0; int fs_converted = 0;
#endif #endif
s->u.ext2_sb.s_mount_opt = 0; set_opt (sb->u.ext2_sb.s_mount_opt, CHECK_NORMAL);
if (!parse_options ((char *) data, &sb_block, if (!parse_options ((char *) data, &sb_block,
&s->u.ext2_sb.s_mount_opt)) { &sb->u.ext2_sb.s_mount_opt)) {
s->s_dev = 0; sb->s_dev = 0;
return NULL; return NULL;
} }
lock_super (s); lock_super (sb);
set_blocksize (dev, BLOCK_SIZE); set_blocksize (dev, BLOCK_SIZE);
if (!(bh = bread (dev, sb_block, BLOCK_SIZE))) { if (!(bh = bread (dev, sb_block, BLOCK_SIZE))) {
s->s_dev = 0; sb->s_dev = 0;
unlock_super (s); unlock_super (sb);
printk ("EXT2-fs: unable to read superblock\n"); printk ("EXT2-fs: unable to read superblock\n");
return NULL; return NULL;
} }
/*
* Note: s_es must be initialized s_es as soon as possible because
* some ext2 macro-instructions depend on its value
*/
es = (struct ext2_super_block *) bh->b_data; es = (struct ext2_super_block *) bh->b_data;
/* Note: s_es must be initialized s_es as soon as possible because sb->u.ext2_sb.s_es = es;
some ext2 macro-instructions depend on its value */ sb->s_magic = es->s_magic;
s->u.ext2_sb.s_es = es; if (sb->s_magic != EXT2_SUPER_MAGIC
s->s_magic = es->s_magic;
if (s->s_magic != EXT2_SUPER_MAGIC
#ifdef EXT2FS_PRE_02B_COMPAT #ifdef EXT2FS_PRE_02B_COMPAT
&& s->s_magic != EXT2_PRE_02B_MAGIC && sb->s_magic != EXT2_PRE_02B_MAGIC
#endif #endif
) { ) {
s->s_dev = 0; sb->s_dev = 0;
unlock_super (s); unlock_super (sb);
brelse (bh); brelse (bh);
if (!silent) if (!silent)
printk ("VFS: Can't find an ext2 filesystem on dev 0x%04x.\n", printk ("VFS: Can't find an ext2 filesystem on dev 0x%04x.\n",
dev); dev);
return NULL; return NULL;
} }
s->s_blocksize = EXT2_MIN_BLOCK_SIZE << es->s_log_block_size; sb->s_blocksize = EXT2_MIN_BLOCK_SIZE << es->s_log_block_size;
s->s_blocksize_bits = EXT2_BLOCK_SIZE_BITS(s); sb->s_blocksize_bits = EXT2_BLOCK_SIZE_BITS(sb);
if (s->s_blocksize != BLOCK_SIZE && if (sb->s_blocksize != BLOCK_SIZE &&
(s->s_blocksize == 1024 || s->s_blocksize == 2048 || (sb->s_blocksize == 1024 || sb->s_blocksize == 2048 ||
s->s_blocksize == 4096)) { sb->s_blocksize == 4096)) {
unsigned long offset; unsigned long offset;
brelse (bh); brelse (bh);
set_blocksize (dev, s->s_blocksize); set_blocksize (dev, sb->s_blocksize);
logic_sb_block = sb_block / s->s_blocksize; logic_sb_block = sb_block / sb->s_blocksize;
offset = sb_block % s->s_blocksize; offset = sb_block % sb->s_blocksize;
bh = bread (dev, logic_sb_block, s->s_blocksize); bh = bread (dev, logic_sb_block, sb->s_blocksize);
if(!bh) if(!bh)
return NULL; return NULL;
es = (struct ext2_super_block *) (((char *)bh->b_data) + offset); es = (struct ext2_super_block *) (((char *)bh->b_data) + offset);
s->u.ext2_sb.s_es = es; sb->u.ext2_sb.s_es = es;
if (es->s_magic != EXT2_SUPER_MAGIC) { if (es->s_magic != EXT2_SUPER_MAGIC) {
s->s_dev = 0; sb->s_dev = 0;
unlock_super (s); unlock_super (sb);
brelse (bh); brelse (bh);
printk ("EXT2-fs: Magic mismatch, very weird !\n"); printk ("EXT2-fs: Magic mismatch, very weird !\n");
return NULL; return NULL;
} }
} }
s->u.ext2_sb.s_frag_size = EXT2_MIN_FRAG_SIZE << sb->u.ext2_sb.s_frag_size = EXT2_MIN_FRAG_SIZE <<
es->s_log_frag_size; es->s_log_frag_size;
if (s->u.ext2_sb.s_frag_size) if (sb->u.ext2_sb.s_frag_size)
s->u.ext2_sb.s_frags_per_block = s->s_blocksize / sb->u.ext2_sb.s_frags_per_block = sb->s_blocksize /
s->u.ext2_sb.s_frag_size; sb->u.ext2_sb.s_frag_size;
else else
s->s_magic = 0; sb->s_magic = 0;
s->u.ext2_sb.s_blocks_per_group = es->s_blocks_per_group; sb->u.ext2_sb.s_blocks_per_group = es->s_blocks_per_group;
s->u.ext2_sb.s_frags_per_group = es->s_frags_per_group; sb->u.ext2_sb.s_frags_per_group = es->s_frags_per_group;
s->u.ext2_sb.s_inodes_per_group = es->s_inodes_per_group; sb->u.ext2_sb.s_inodes_per_group = es->s_inodes_per_group;
s->u.ext2_sb.s_inodes_per_block = s->s_blocksize / sb->u.ext2_sb.s_inodes_per_block = sb->s_blocksize /
sizeof (struct ext2_inode); sizeof (struct ext2_inode);
s->u.ext2_sb.s_desc_per_block = s->s_blocksize / sb->u.ext2_sb.s_itb_per_group = sb->u.ext2_sb.s_inodes_per_group /
sb->u.ext2_sb.s_inodes_per_block;
sb->u.ext2_sb.s_desc_per_block = sb->s_blocksize /
sizeof (struct ext2_group_desc); sizeof (struct ext2_group_desc);
s->u.ext2_sb.s_sbh = bh; sb->u.ext2_sb.s_sbh = bh;
s->u.ext2_sb.s_es = es; sb->u.ext2_sb.s_es = es;
s->u.ext2_sb.s_mount_state = es->s_state; sb->u.ext2_sb.s_mount_state = es->s_state;
s->u.ext2_sb.s_rename_lock = 0; sb->u.ext2_sb.s_rename_lock = 0;
s->u.ext2_sb.s_rename_wait = NULL; sb->u.ext2_sb.s_rename_wait = NULL;
#ifdef EXT2FS_PRE_02B_COMPAT #ifdef EXT2FS_PRE_02B_COMPAT
if (s->s_magic == EXT2_PRE_02B_MAGIC) { if (sb->s_magic == EXT2_PRE_02B_MAGIC) {
if (es->s_blocks_count > 262144) { if (es->s_blocks_count > 262144) {
/* fs > 256 MB can't be converted */ /*
s->s_dev = 0; * fs > 256 MB can't be converted
unlock_super (s); */
sb->s_dev = 0;
unlock_super (sb);
brelse (bh); brelse (bh);
printk ("EXT2-fs: trying to mount a pre-0.2b file" printk ("EXT2-fs: trying to mount a pre-0.2b file"
"system which cannot be converted\n"); "system which cannot be converted\n");
...@@ -301,16 +454,16 @@ struct super_block * ext2_read_super (struct super_block * s, void * data, ...@@ -301,16 +454,16 @@ struct super_block * ext2_read_super (struct super_block * s, void * data,
} }
printk ("EXT2-fs: mounting a pre 0.2b file system, " printk ("EXT2-fs: mounting a pre 0.2b file system, "
"will try to convert the structure\n"); "will try to convert the structure\n");
if (!(s->s_flags & MS_RDONLY)) { if (!(sb->s_flags & MS_RDONLY)) {
s->s_dev = 0; sb->s_dev = 0;
unlock_super (s); unlock_super (sb);
brelse (bh); brelse (bh);
printk ("EXT2-fs: cannot convert a read-only fs\n"); printk ("EXT2-fs: cannot convert a read-only fs\n");
return NULL; return NULL;
} }
if (!convert_pre_02b_fs (s, bh)) { if (!convert_pre_02b_fs (sb, bh)) {
s->s_dev = 0; sb->s_dev = 0;
unlock_super (s); unlock_super (sb);
brelse (bh); brelse (bh);
printk ("EXT2-fs: conversion failed !!!\n"); printk ("EXT2-fs: conversion failed !!!\n");
return NULL; return NULL;
...@@ -319,18 +472,18 @@ struct super_block * ext2_read_super (struct super_block * s, void * data, ...@@ -319,18 +472,18 @@ struct super_block * ext2_read_super (struct super_block * s, void * data,
fs_converted = 1; fs_converted = 1;
} }
#endif #endif
if (s->s_magic != EXT2_SUPER_MAGIC) { if (sb->s_magic != EXT2_SUPER_MAGIC) {
s->s_dev = 0; sb->s_dev = 0;
unlock_super (s); unlock_super (sb);
brelse (bh); brelse (bh);
if (!silent) if (!silent)
printk ("VFS: Can't find an ext2 filesystem on dev 0x%04x.\n", printk ("VFS: Can't find an ext2 filesystem on dev 0x%04x.\n",
dev); dev);
return NULL; return NULL;
} }
if (s->s_blocksize != bh->b_size) { if (sb->s_blocksize != bh->b_size) {
s->s_dev = 0; sb->s_dev = 0;
unlock_super (s); unlock_super (sb);
brelse (bh); brelse (bh);
if (!silent) if (!silent)
printk ("VFS: Unsupported blocksize on dev 0x%04x.\n", printk ("VFS: Unsupported blocksize on dev 0x%04x.\n",
...@@ -338,98 +491,84 @@ struct super_block * ext2_read_super (struct super_block * s, void * data, ...@@ -338,98 +491,84 @@ struct super_block * ext2_read_super (struct super_block * s, void * data,
return NULL; return NULL;
} }
if (s->s_blocksize != s->u.ext2_sb.s_frag_size) { if (sb->s_blocksize != sb->u.ext2_sb.s_frag_size) {
s->s_dev = 0; sb->s_dev = 0;
unlock_super (s); unlock_super (sb);
brelse (bh); brelse (bh);
printk ("EXT2-fs: fragsize %lu != blocksize %lu (not supported yet)\n", printk ("EXT2-fs: fragsize %lu != blocksize %lu (not supported yet)\n",
s->u.ext2_sb.s_frag_size, s->s_blocksize); sb->u.ext2_sb.s_frag_size, sb->s_blocksize);
return NULL; return NULL;
} }
s->u.ext2_sb.s_groups_count = (es->s_blocks_count - sb->u.ext2_sb.s_groups_count = (es->s_blocks_count -
es->s_first_data_block + es->s_first_data_block +
EXT2_BLOCKS_PER_GROUP(s) - 1) / EXT2_BLOCKS_PER_GROUP(sb) - 1) /
EXT2_BLOCKS_PER_GROUP(s); EXT2_BLOCKS_PER_GROUP(sb);
for (i = 0; i < EXT2_MAX_GROUP_DESC; i++) for (i = 0; i < EXT2_MAX_GROUP_DESC; i++)
s->u.ext2_sb.s_group_desc[i] = NULL; sb->u.ext2_sb.s_group_desc[i] = NULL;
bh_count = (s->u.ext2_sb.s_groups_count + EXT2_DESC_PER_BLOCK(s) - 1) / bh_count = (sb->u.ext2_sb.s_groups_count + EXT2_DESC_PER_BLOCK(sb) - 1) /
EXT2_DESC_PER_BLOCK(s); EXT2_DESC_PER_BLOCK(sb);
if (bh_count > EXT2_MAX_GROUP_DESC) { if (bh_count > EXT2_MAX_GROUP_DESC) {
s->s_dev = 0; sb->s_dev = 0;
unlock_super (s); unlock_super (sb);
brelse (bh); brelse (bh);
printk ("EXT2-fs: file system is too big\n"); printk ("EXT2-fs: file system is too big\n");
return NULL; return NULL;
} }
for (i = 0; i < bh_count; i++) { for (i = 0; i < bh_count; i++) {
s->u.ext2_sb.s_group_desc[i] = bread (dev, logic_sb_block + i + 1, sb->u.ext2_sb.s_group_desc[i] = bread (dev, logic_sb_block + i + 1,
s->s_blocksize); sb->s_blocksize);
if (!s->u.ext2_sb.s_group_desc[i]) { if (!sb->u.ext2_sb.s_group_desc[i]) {
s->s_dev = 0; sb->s_dev = 0;
unlock_super (s); unlock_super (sb);
for (j = 0; j < i; j++) for (j = 0; j < i; j++)
brelse (s->u.ext2_sb.s_group_desc[i]); brelse (sb->u.ext2_sb.s_group_desc[i]);
brelse (bh); brelse (bh);
printk ("EXT2-fs: unable to read group descriptors\n"); printk ("EXT2-fs: unable to read group descriptors\n");
return NULL; return NULL;
} }
} }
if (!ext2_check_descriptors (sb)) {
sb->s_dev = 0;
unlock_super (sb);
for (j = 0; j < i; j++)
brelse (sb->u.ext2_sb.s_group_desc[i]);
brelse (bh);
printk ("EXT2-fs: group descriptors corrupted !\n");
return NULL;
}
for (i = 0; i < EXT2_MAX_GROUP_LOADED; i++) { for (i = 0; i < EXT2_MAX_GROUP_LOADED; i++) {
s->u.ext2_sb.s_inode_bitmap_number[i] = 0; sb->u.ext2_sb.s_inode_bitmap_number[i] = 0;
s->u.ext2_sb.s_inode_bitmap[i] = NULL; sb->u.ext2_sb.s_inode_bitmap[i] = NULL;
s->u.ext2_sb.s_block_bitmap_number[i] = 0; sb->u.ext2_sb.s_block_bitmap_number[i] = 0;
s->u.ext2_sb.s_block_bitmap[i] = NULL; sb->u.ext2_sb.s_block_bitmap[i] = NULL;
} }
s->u.ext2_sb.s_loaded_inode_bitmaps = 0; sb->u.ext2_sb.s_loaded_inode_bitmaps = 0;
s->u.ext2_sb.s_loaded_block_bitmaps = 0; sb->u.ext2_sb.s_loaded_block_bitmaps = 0;
unlock_super (s); unlock_super (sb);
/* set up enough so that it can read an inode */ /*
s->s_dev = dev; * set up enough so that it can read an inode
s->s_op = &ext2_sops; */
if (!(s->s_mounted = iget (s, EXT2_ROOT_INO))) { sb->s_dev = dev;
s->s_dev = 0; sb->s_op = &ext2_sops;
if (!(sb->s_mounted = iget (sb, EXT2_ROOT_INO))) {
sb->s_dev = 0;
for (i = 0; i < EXT2_MAX_GROUP_DESC; i++) for (i = 0; i < EXT2_MAX_GROUP_DESC; i++)
if (s->u.ext2_sb.s_group_desc[i]) if (sb->u.ext2_sb.s_group_desc[i])
brelse (s->u.ext2_sb.s_group_desc[i]); brelse (sb->u.ext2_sb.s_group_desc[i]);
brelse (bh); brelse (bh);
printk ("EXT2-fs: get root inode failed\n"); printk ("EXT2-fs: get root inode failed\n");
return NULL; return NULL;
} }
if (!(s->s_flags & MS_RDONLY)) {
es->s_state &= ~EXT2_VALID_FS;
if (!es->s_max_mnt_count)
es->s_max_mnt_count = EXT2_DFL_MAX_MNT_COUNT;
es->s_mnt_count++;
es->s_mtime = CURRENT_TIME;
bh->b_dirt = 1;
s->s_dirt = 1;
}
#ifdef EXT2FS_PRE_02B_COMPAT #ifdef EXT2FS_PRE_02B_COMPAT
if (fs_converted) { if (fs_converted) {
for (i = 0; i < bh_count; i++) for (i = 0; i < bh_count; i++)
s->u.ext2_sb.s_group_desc[i]->b_dirt = 1; sb->u.ext2_sb.s_group_desc[i]->b_dirt = 1;
s->s_dirt = 1; sb->s_dirt = 1;
} }
#endif #endif
if (!(s->u.ext2_sb.s_mount_state & EXT2_VALID_FS)) ext2_setup_super (sb, es);
printk ("EXT2-fs warning: mounting unchecked file system, " return sb;
"running e2fsck is recommended\n");
else if (s->u.ext2_sb.s_mount_state & EXT2_ERROR_FS)
printk ("EXT2-fs warning: mounting file system with errors, "
"running e2fsck is recommended\n");
else if (es->s_mnt_count >= es->s_max_mnt_count)
printk ("EXT2-fs warning: maximal mount count reached, "
"running e2fsck is recommended\n");
if (s->u.ext2_sb.s_mount_opt & EXT2_MOUNT_CHECK) {
printk ("[EXT II FS %s, %s, bs=%lu, fs=%lu, gc=%lu, bpg=%lu, ipg=%lu]\n",
EXT2FS_VERSION, EXT2FS_DATE, s->s_blocksize,
s->u.ext2_sb.s_frag_size, s->u.ext2_sb.s_groups_count,
EXT2_BLOCKS_PER_GROUP(s), EXT2_INODES_PER_GROUP(s));
ext2_check_blocks_bitmap (s);
ext2_check_inodes_bitmap (s);
}
return s;
} }
static void ext2_commit_super (struct super_block * sb, static void ext2_commit_super (struct super_block * sb,
...@@ -469,9 +608,16 @@ void ext2_write_super (struct super_block * sb) ...@@ -469,9 +608,16 @@ void ext2_write_super (struct super_block * sb)
sb->s_dirt = 0; sb->s_dirt = 0;
} }
int ext2_remount (struct super_block * sb, int * flags) int ext2_remount (struct super_block * sb, int * flags, char * data)
{ {
struct ext2_super_block * es; struct ext2_super_block * es;
unsigned long tmp;
/*
* Allow the "check" option to be passed as a remount option.
*/
set_opt (sb->u.ext2_sb.s_mount_opt, CHECK_NORMAL);
parse_options (data, &tmp, &sb->u.ext2_sb.s_mount_opt);
es = sb->u.ext2_sb.s_es; es = sb->u.ext2_sb.s_es;
if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY)) if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY))
...@@ -480,9 +626,10 @@ int ext2_remount (struct super_block * sb, int * flags) ...@@ -480,9 +626,10 @@ int ext2_remount (struct super_block * sb, int * flags)
if (es->s_state & EXT2_VALID_FS || if (es->s_state & EXT2_VALID_FS ||
!(sb->u.ext2_sb.s_mount_state & EXT2_VALID_FS)) !(sb->u.ext2_sb.s_mount_state & EXT2_VALID_FS))
return 0; return 0;
/* OK, we are remounting a valid rw partition rdonly, so set /*
the rdonly flag and then mark the partition as valid * OK, we are remounting a valid rw partition rdonly, so set
again. */ * the rdonly flag and then mark the partition as valid again.
*/
es->s_state = sb->u.ext2_sb.s_mount_state; es->s_state = sb->u.ext2_sb.s_mount_state;
es->s_mtime = CURRENT_TIME; es->s_mtime = CURRENT_TIME;
sb->u.ext2_sb.s_sbh->b_dirt = 1; sb->u.ext2_sb.s_sbh->b_dirt = 1;
...@@ -490,26 +637,14 @@ int ext2_remount (struct super_block * sb, int * flags) ...@@ -490,26 +637,14 @@ int ext2_remount (struct super_block * sb, int * flags)
ext2_commit_super (sb, es); ext2_commit_super (sb, es);
} }
else { else {
/* Mounting a RDONLY partition read-write, so reread and /*
store the current valid flag. (It may have been changed * Mounting a RDONLY partition read-write, so reread and
by e2fsck since we originally mounted the partition.) */ * store the current valid flag. (It may have been changed
* by e2fsck since we originally mounted the partition.)
*/
sb->u.ext2_sb.s_mount_state = es->s_state; sb->u.ext2_sb.s_mount_state = es->s_state;
es->s_state &= ~EXT2_VALID_FS; sb->s_flags &= ~MS_RDONLY;
if (!es->s_max_mnt_count) ext2_setup_super (sb, es);
es->s_max_mnt_count = EXT2_DFL_MAX_MNT_COUNT;
es->s_mnt_count++;
es->s_mtime = CURRENT_TIME;
sb->u.ext2_sb.s_sbh->b_dirt = 1;
sb->s_dirt = 1;
if (!(sb->u.ext2_sb.s_mount_state & EXT2_VALID_FS))
printk ("EXT2-fs warning: remounting unchecked fs, "
"running e2fsck is recommended\n");
else if ((sb->u.ext2_sb.s_mount_state & EXT2_ERROR_FS))
printk ("EXT2-fs warning: remounting fs with errors, "
"running e2fsck is recommended\n");
else if (es->s_mnt_count >= es->s_max_mnt_count)
printk ("EXT2-fs warning: maximal mount count reached, "
"running e2fsck is recommended\n");
} }
return 0; return 0;
} }
......
/* /*
* linux/fs/ext2/symlink.c * linux/fs/ext2/symlink.c
* *
* Copyright (C) 1992, 1993 Remy Card (card@masi.ibp.fr) * Copyright (C) 1992, 1993, 1994 Remy Card (card@masi.ibp.fr)
* Laboratoire MASI - Institut Blaise Pascal
* Universite Pierre et Marie Curie (Paris VI)
* *
* from * from
* *
......
/* /*
* linux/fs/ext2/truncate.c * linux/fs/ext2/truncate.c
* *
* Copyright (C) 1992, 1993 Remy Card (card@masi.ibp.fr) * Copyright (C) 1992, 1993, 1994 Remy Card (card@masi.ibp.fr)
* Laboratoire MASI - Institut Blaise Pascal
* Universite Pierre et Marie Curie (Paris VI)
* *
* from * from
* *
...@@ -80,7 +82,7 @@ static int trunc_direct (struct inode * inode) ...@@ -80,7 +82,7 @@ static int trunc_direct (struct inode * inode)
bh->b_dirt = 1; bh->b_dirt = 1;
} }
brelse (bh); brelse (bh);
ext2_free_block (inode->i_sb, tmp); ext2_free_blocks (inode->i_sb, tmp, 1);
} }
return retry; return retry;
} }
...@@ -142,7 +144,7 @@ static int trunc_indirect (struct inode * inode, int offset, unsigned long * p) ...@@ -142,7 +144,7 @@ static int trunc_indirect (struct inode * inode, int offset, unsigned long * p)
bh->b_dirt = 1; bh->b_dirt = 1;
} }
brelse (bh); brelse (bh);
ext2_free_block (inode->i_sb, tmp); ext2_free_blocks (inode->i_sb, tmp, 1);
inode->i_blocks -= blocks; inode->i_blocks -= blocks;
inode->i_dirt = 1; inode->i_dirt = 1;
} }
...@@ -158,7 +160,7 @@ static int trunc_indirect (struct inode * inode, int offset, unsigned long * p) ...@@ -158,7 +160,7 @@ static int trunc_indirect (struct inode * inode, int offset, unsigned long * p)
*p = 0; *p = 0;
inode->i_blocks -= blocks; inode->i_blocks -= blocks;
inode->i_dirt = 1; inode->i_dirt = 1;
ext2_free_block (inode->i_sb, tmp); ext2_free_blocks (inode->i_sb, tmp, 1);
} }
if (IS_SYNC(inode) && ind_bh->b_dirt) { if (IS_SYNC(inode) && ind_bh->b_dirt) {
ll_rw_block (WRITE, 1, &ind_bh); ll_rw_block (WRITE, 1, &ind_bh);
...@@ -218,7 +220,7 @@ static int trunc_dindirect (struct inode * inode, int offset, ...@@ -218,7 +220,7 @@ static int trunc_dindirect (struct inode * inode, int offset,
*p = 0; *p = 0;
inode->i_blocks -= blocks; inode->i_blocks -= blocks;
inode->i_dirt = 1; inode->i_dirt = 1;
ext2_free_block (inode->i_sb, tmp); ext2_free_blocks (inode->i_sb, tmp, 1);
} }
if (IS_SYNC(inode) && dind_bh->b_dirt) { if (IS_SYNC(inode) && dind_bh->b_dirt) {
ll_rw_block (WRITE, 1, &dind_bh); ll_rw_block (WRITE, 1, &dind_bh);
...@@ -277,7 +279,7 @@ static int trunc_tindirect (struct inode * inode) ...@@ -277,7 +279,7 @@ static int trunc_tindirect (struct inode * inode)
*p = 0; *p = 0;
inode->i_blocks -= blocks; inode->i_blocks -= blocks;
inode->i_dirt = 1; inode->i_dirt = 1;
ext2_free_block (inode->i_sb, tmp); ext2_free_blocks (inode->i_sb, tmp, 1);
} }
if (IS_SYNC(inode) && tind_bh->b_dirt) { if (IS_SYNC(inode) && tind_bh->b_dirt) {
ll_rw_block (WRITE, 1, &tind_bh); ll_rw_block (WRITE, 1, &tind_bh);
...@@ -294,6 +296,7 @@ void ext2_truncate (struct inode * inode) ...@@ -294,6 +296,7 @@ void ext2_truncate (struct inode * inode)
if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
S_ISLNK(inode->i_mode))) S_ISLNK(inode->i_mode)))
return; return;
ext2_discard_prealloc(inode);
while (1) { while (1) {
retry = trunc_direct(inode); retry = trunc_direct(inode);
retry |= trunc_indirect (inode, EXT2_IND_BLOCK, retry |= trunc_indirect (inode, EXT2_IND_BLOCK,
...@@ -312,13 +315,3 @@ void ext2_truncate (struct inode * inode) ...@@ -312,13 +315,3 @@ void ext2_truncate (struct inode * inode)
inode->i_mtime = inode->i_ctime = CURRENT_TIME; inode->i_mtime = inode->i_ctime = CURRENT_TIME;
inode->i_dirt = 1; inode->i_dirt = 1;
} }
/*
* Called when a inode is released. Note that this is different
* from ext2_open: open gets called at every open, but release
* gets called only when /all/ the files are closed.
*/
void ext2_release (struct inode * inode, struct file * filp)
{
printk ("ext2_release not implemented\n");
}
...@@ -36,7 +36,7 @@ extern int root_mountflags; ...@@ -36,7 +36,7 @@ extern int root_mountflags;
struct super_block super_blocks[NR_SUPER]; struct super_block super_blocks[NR_SUPER];
static int do_remount_sb(struct super_block *sb, int flags); static int do_remount_sb(struct super_block *sb, int flags, char * data);
/* this is initialized in init/main.c */ /* this is initialized in init/main.c */
dev_t ROOT_DEV = 0; dev_t ROOT_DEV = 0;
...@@ -210,7 +210,7 @@ static int do_umount(dev_t dev) ...@@ -210,7 +210,7 @@ static int do_umount(dev_t dev)
if (!(sb=get_super(dev))) if (!(sb=get_super(dev)))
return -ENOENT; return -ENOENT;
if (!(sb->s_flags & MS_RDONLY)) { if (!(sb->s_flags & MS_RDONLY)) {
retval = do_remount_sb(sb, MS_RDONLY); retval = do_remount_sb(sb, MS_RDONLY, 0);
if (retval) if (retval)
return retval; return retval;
} }
...@@ -344,7 +344,7 @@ static int do_mount(dev_t dev, const char * dir, char * type, int flags, void * ...@@ -344,7 +344,7 @@ static int do_mount(dev_t dev, const char * dir, char * type, int flags, void *
* FS-specific mount options can't be altered by remounting. * FS-specific mount options can't be altered by remounting.
*/ */
static int do_remount_sb(struct super_block *sb, int flags) static int do_remount_sb(struct super_block *sb, int flags, char *data)
{ {
int retval; int retval;
...@@ -353,7 +353,7 @@ static int do_remount_sb(struct super_block *sb, int flags) ...@@ -353,7 +353,7 @@ static int do_remount_sb(struct super_block *sb, int flags)
if (!fs_may_remount_ro(sb->s_dev)) if (!fs_may_remount_ro(sb->s_dev))
return -EBUSY; return -EBUSY;
if (sb->s_op && sb->s_op->remount_fs) { if (sb->s_op && sb->s_op->remount_fs) {
retval = sb->s_op->remount_fs(sb, &flags); retval = sb->s_op->remount_fs(sb, &flags, data);
if (retval) if (retval)
return retval; return retval;
} }
...@@ -362,7 +362,7 @@ static int do_remount_sb(struct super_block *sb, int flags) ...@@ -362,7 +362,7 @@ static int do_remount_sb(struct super_block *sb, int flags)
return 0; return 0;
} }
static int do_remount(const char *dir,int flags) static int do_remount(const char *dir,int flags,char *data)
{ {
struct inode *dir_i; struct inode *dir_i;
int retval; int retval;
...@@ -374,23 +374,54 @@ static int do_remount(const char *dir,int flags) ...@@ -374,23 +374,54 @@ static int do_remount(const char *dir,int flags)
iput(dir_i); iput(dir_i);
return -EINVAL; return -EINVAL;
} }
retval = do_remount_sb(dir_i->i_sb, flags); retval = do_remount_sb(dir_i->i_sb, flags, data);
iput(dir_i); iput(dir_i);
return retval; return retval;
} }
static int copy_mount_options (char * data, unsigned long *where)
{
int i;
unsigned long page;
struct vm_area_struct * vma;
*where = 0;
if (!data)
return 0;
for (vma = current->mmap ; ; ) {
if (!vma ||
(unsigned long) data < vma->vm_start) {
return -EFAULT;
}
if ((unsigned long) data < vma->vm_end)
break;
vma = vma->vm_next;
}
i = vma->vm_end - (unsigned long) data;
if (PAGE_SIZE <= (unsigned long) i)
i = PAGE_SIZE-1;
if (!(page = __get_free_page(GFP_KERNEL))) {
return -ENOMEM;
}
memcpy_fromfs((void *) page,data,i);
*where = page;
return 0;
}
/* /*
* Flags is a 16-bit value that allows up to 16 non-fs dependent flags to * Flags is a 16-bit value that allows up to 16 non-fs dependent flags to
* be given to the mount() call (ie: read-only, no-dev, no-suid etc). * be given to the mount() call (ie: read-only, no-dev, no-suid etc).
* *
* data is a (void *) that can point to any structure up to PAGE_SIZE-1 bytes, which * data is a (void *) that can point to any structure up to
* can contain arbitrary fs-dependent information (or be NULL). * PAGE_SIZE-1 bytes, which can contain arbitrary fs-dependent
* information (or be NULL).
* *
* NOTE! As old versions of mount() didn't use this setup, the flags has to have * NOTE! As old versions of mount() didn't use this setup, the flags
* a special 16-bit magic number in the hight word: 0xC0ED. If this magic word * has to have a special 16-bit magic number in the hight word:
* isn't present, the flags and data info isn't used, as the syscall assumes we * 0xC0ED. If this magic word isn't present, the flags and data info
* are talking to an older version that didn't understand them. * isn't used, as the syscall assumes we are talking to an older
* version that didn't understand them.
*/ */
asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type, asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type,
unsigned long new_flags, void * data) unsigned long new_flags, void * data)
...@@ -400,27 +431,29 @@ asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type, ...@@ -400,27 +431,29 @@ asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type,
struct file_operations * fops; struct file_operations * fops;
dev_t dev; dev_t dev;
int retval; int retval;
char tmp[100], * t; char * t;
int i;
unsigned long flags = 0; unsigned long flags = 0;
unsigned long page = 0; unsigned long page = 0;
if (!suser()) if (!suser())
return -EPERM; return -EPERM;
if ((new_flags & (MS_MGC_MSK | MS_REMOUNT)) == (MS_MGC_VAL | MS_REMOUNT)) { if ((new_flags &
return do_remount(dir_name,new_flags & ~MS_MGC_MSK & ~MS_REMOUNT); (MS_MGC_MSK | MS_REMOUNT)) == (MS_MGC_VAL | MS_REMOUNT)) {
} retval = copy_mount_options (data, &page);
if (type) { if (retval < 0)
for (i = 0 ; i < 100 ; i++) { return retval;
if (TASK_SIZE <= (unsigned long) type) retval = do_remount(dir_name,
return -EFAULT; new_flags & ~MS_MGC_MSK & ~MS_REMOUNT,
if (!(tmp[i] = get_fs_byte(type++))) (char *) page);
break; free_page(page);
return retval;
} }
t = tmp; retval = copy_mount_options (type, &page);
} else if (retval < 0)
t = NULL; return retval;
if (!(fstype = get_fs_type(t))) fstype = get_fs_type((char *) page);
free_page(page);
if (!fstype)
return -ENODEV; return -ENODEV;
t = fstype->name; t = fstype->name;
if (fstype->requires_dev) { if (fstype->requires_dev) {
...@@ -455,26 +488,10 @@ asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type, ...@@ -455,26 +488,10 @@ asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type,
} }
if ((new_flags & MS_MGC_MSK) == MS_MGC_VAL) { if ((new_flags & MS_MGC_MSK) == MS_MGC_VAL) {
flags = new_flags & ~MS_MGC_MSK; flags = new_flags & ~MS_MGC_MSK;
if (data) { retval = copy_mount_options(data, &page);
struct vm_area_struct * vma; if (retval < 0) {
for (vma = current->mmap ; ; ) {
if (!vma || (unsigned long) data < vma->vm_start) {
iput(inode); iput(inode);
return -EFAULT; return retval;
}
if ((unsigned long) data < vma->vm_end)
break;
vma = vma->vm_next;
}
i = vma->vm_end - (unsigned long) data;
if (PAGE_SIZE <= (unsigned long) i)
i = PAGE_SIZE-1;
if (!(page = __get_free_page(GFP_KERNEL))) {
iput(inode);
return -ENOMEM;
}
memcpy_fromfs((void *) page,data,i);
} }
} }
retval = do_mount(dev,dir_name,t,flags,(void *) page); retval = do_mount(dev,dir_name,t,flags,(void *) page);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* to guarantee better timings even on fast machines. * to guarantee better timings even on fast machines.
* *
* On the other hand, I'd like to be sure of a non-existent port: * On the other hand, I'd like to be sure of a non-existent port:
* I feel a bit unsafe about using 0x80. * I feel a bit unsafe about using 0x80 (should be safe, though)
* *
* Linus * Linus
*/ */
...@@ -24,73 +24,41 @@ ...@@ -24,73 +24,41 @@
#define SLOW_DOWN_IO __SLOW_DOWN_IO #define SLOW_DOWN_IO __SLOW_DOWN_IO
#endif #endif
/* This is the more general version of outb.. */ /*
extern inline void __outb(unsigned char value, unsigned short port) * Talk about misusing macros..
{ */
__asm__ __volatile__ ("outb %b0,%w1"
: /* no outputs */ #define __OUT1(s,x) \
:"a" (value),"d" (port)); extern inline void __out##s(unsigned x value, unsigned short port) {
}
#define __OUT2(s,s1,s2) \
/* this is used for constant port numbers < 256.. */ __asm__ __volatile__ ("out" #s " %" s1 "0,%" s2 "1"
extern inline void __outbc(unsigned char value, unsigned short port)
{ #define __OUT(s,s1,x) \
__asm__ __volatile__ ("outb %b0,%1" __OUT1(s,x) __OUT2(s,s1,"w") : : "a" (value), "d" (port)); } \
: /* no outputs */ __OUT1(s##c,x) __OUT2(s,s1,"") : : "a" (value), "i" (port)); } \
:"a" (value),"i" (port)); __OUT1(s##_p,x) __OUT2(s,s1,"w") : : "a" (value), "d" (port)); SLOW_DOWN_IO; } \
} __OUT1(s##c_p,x) __OUT2(s,s1,"") : : "a" (value), "i" (port)); SLOW_DOWN_IO; }
/* general version of inb */ #define __IN1(s) \
extern inline unsigned int __inb(unsigned short port) extern inline unsigned int __in##s(unsigned short port) { unsigned int _v;
{
unsigned int _v; #define __IN2(s,s1,s2) \
__asm__ __volatile__ ("inb %w1,%b0" __asm__ __volatile__ ("in" #s " %" s2 "1,%" s1 "0"
:"=a" (_v):"d" (port),"0" (0));
return _v; #define __IN(s,s1,i...) \
} __IN1(s) __IN2(s,s1,"w") : "=a" (_v) : "d" (port) ,##i ); return _v; } \
__IN1(s##c) __IN2(s,s1,"") : "=a" (_v) : "i" (port) ,##i ); return _v; } \
/* inb with constant port nr 0-255 */ __IN1(s##_p) __IN2(s,s1,"w") : "=a" (_v) : "d" (port) ,##i ); SLOW_DOWN_IO; return _v; } \
extern inline unsigned int __inbc(unsigned short port) __IN1(s##c_p) __IN2(s,s1,"") : "=a" (_v) : "i" (port) ,##i ); SLOW_DOWN_IO; return _v; }
{
unsigned int _v; __IN(b,"b","0" (0))
__asm__ __volatile__ ("inb %1,%b0" __IN(w,"w","0" (0))
:"=a" (_v):"i" (port),"0" (0)); __IN(l,"")
return _v;
} __OUT(b,"b",char)
__OUT(w,"w",short)
extern inline void __outb_p(unsigned char value, unsigned short port) __OUT(l,,int)
{
__asm__ __volatile__ ("outb %b0,%w1"
: /* no outputs */
:"a" (value),"d" (port));
SLOW_DOWN_IO;
}
extern inline void __outbc_p(unsigned char value, unsigned short port)
{
__asm__ __volatile__ ("outb %b0,%1"
: /* no outputs */
:"a" (value),"i" (port));
SLOW_DOWN_IO;
}
extern inline unsigned int __inb_p(unsigned short port)
{
unsigned int _v;
__asm__ __volatile__ ("inb %w1,%b0"
:"=a" (_v):"d" (port),"0" (0));
SLOW_DOWN_IO;
return _v;
}
extern inline unsigned int __inbc_p(unsigned short port)
{
unsigned int _v;
__asm__ __volatile__ ("inb %1,%b0"
:"=a" (_v):"i" (port),"0" (0));
SLOW_DOWN_IO;
return _v;
}
/* /*
* Note that due to the way __builtin_constant_p() works, you * Note that due to the way __builtin_constant_p() works, you
...@@ -117,4 +85,44 @@ __asm__ __volatile__ ("inb %1,%b0" ...@@ -117,4 +85,44 @@ __asm__ __volatile__ ("inb %1,%b0"
__inbc_p(port) : \ __inbc_p(port) : \
__inb_p(port)) __inb_p(port))
#define outw(val,port) \
((__builtin_constant_p((port)) && (port) < 256) ? \
__outwc((val),(port)) : \
__outw((val),(port)))
#define inw(port) \
((__builtin_constant_p((port)) && (port) < 256) ? \
__inwc(port) : \
__inw(port))
#define outw_p(val,port) \
((__builtin_constant_p((port)) && (port) < 256) ? \
__outwc_p((val),(port)) : \
__outw_p((val),(port)))
#define inw_p(port) \
((__builtin_constant_p((port)) && (port) < 256) ? \
__inwc_p(port) : \
__inw_p(port))
#define outl(val,port) \
((__builtin_constant_p((port)) && (port) < 256) ? \
__outlc((val),(port)) : \
__outl((val),(port)))
#define inl(port) \
((__builtin_constant_p((port)) && (port) < 256) ? \
__inlc(port) : \
__inl(port))
#define outl_p(val,port) \
((__builtin_constant_p((port)) && (port) < 256) ? \
__outlc_p((val),(port)) : \
__outl_p((val),(port)))
#define inl_p(port) \
((__builtin_constant_p((port)) && (port) < 256) ? \
__inlc_p(port) : \
__inl_p(port))
#endif #endif
...@@ -35,7 +35,7 @@ extern void enable_irq(unsigned int); ...@@ -35,7 +35,7 @@ extern void enable_irq(unsigned int);
"movl $" STR(USER_DS) ",%edx\n\t" \ "movl $" STR(USER_DS) ",%edx\n\t" \
"mov %dx,%fs\n\t" \ "mov %dx,%fs\n\t" \
"movl $0,%edx\n\t" \ "movl $0,%edx\n\t" \
"movl %edx,%db7\n" "movl %edx,%db7\n\t"
/* /*
* SAVE_MOST/RESTORE_MOST is used for the faster version of IRQ handlers, * SAVE_MOST/RESTORE_MOST is used for the faster version of IRQ handlers,
......
/* /*
* linux/include/linux/ext2_fs.h * linux/include/linux/ext2_fs.h
* *
* Copyright (C) 1992, 1993 Remy Card (card@masi.ibp.fr) * Copyright (C) 1992, 1993, 1994 Remy Card (card@masi.ibp.fr)
* Laboratoire MASI - Institut Blaise Pascal
* Universite Pierre et Marie Curie (Paris VI)
* *
* from * from
* *
...@@ -38,20 +40,20 @@ ...@@ -38,20 +40,20 @@
#undef EXT2FS_PRE_02B_COMPAT #undef EXT2FS_PRE_02B_COMPAT
/* /*
* Define EXT2FS_PRE_04_COMPAT to convert ext2 fs prior to 0.4 * Define DONT_USE_DCACHE to inhibit the directory cache
*/ */
#define EXT2_PRE_04_COMPAT #define DONT_USE_DCACHE
/* /*
* Define DONT_USE_DCACHE to inhibit the directory cache * Define EXT2_PREALLOCATE to preallocate data blocks for expanding files
*/ */
#define DONT_USE_DCACHE #define EXT2_PREALLOCATE
/* /*
* The second extended file system version * The second extended file system version
*/ */
#define EXT2FS_DATE "93/11/19" #define EXT2FS_DATE "93/12/30"
#define EXT2FS_VERSION "0.4a" #define EXT2FS_VERSION "0.4b"
/* /*
* Debug code * Debug code
...@@ -242,13 +244,33 @@ struct ext2_inode { ...@@ -242,13 +244,33 @@ struct ext2_inode {
/* /*
* Mount flags * Mount flags
*/ */
#define EXT2_MOUNT_CHECK 0x0001 /* Do some more checks */ #define EXT2_MOUNT_CHECK_NORMAL 0x0001 /* Do some more checks */
#define EXT2_MOUNT_CHECK_STRICT 0x0002 /* Do again more checks */
#define EXT2_MOUNT_CHECK (EXT2_MOUNT_CHECK_NORMAL | \
EXT2_MOUNT_CHECK_STRICT)
#define EXT2_MOUNT_GRPID 0x0004 /* Create files with directory's group */
#define EXT2_MOUNT_DEBUG 0x0008 /* Some debugging messages */
#define EXT2_MOUNT_ERRORS_CONT 0x0010 /* Continue on errors */
#define EXT2_MOUNT_ERRORS_RO 0x0020 /* Remount fs ro on errors */
#define EXT2_MOUNT_ERRORS_PANIC 0x0040 /* Panic on errors */
#define clear_opt(o, opt) o &= ~EXT2_MOUNT_##opt
#define set_opt(o, opt) o |= EXT2_MOUNT_##opt
#define test_opt(sb, opt) ((sb)->u.ext2_sb.s_mount_opt & \
EXT2_MOUNT_##opt)
/* /*
* Maximal mount counts between two filesystem checks * Maximal mount counts between two filesystem checks
*/ */
#define EXT2_DFL_MAX_MNT_COUNT 20 /* Allow 20 mounts */ #define EXT2_DFL_MAX_MNT_COUNT 20 /* Allow 20 mounts */
/*
* Behaviour when detecting errors
*/
#define EXT2_ERRORS_CONTINUE 1 /* Continue execution */
#define EXT2_ERRORS_RO 2 /* Remount fs read-only */
#define EXT2_ERRORS_PANIC 3 /* Panic */
#define EXT2_ERRORS_DEFAULT EXT2_ERRORS_CONTINUE
/* /*
* Structure of the super block * Structure of the super block
*/ */
...@@ -270,7 +292,9 @@ struct ext2_super_block { ...@@ -270,7 +292,9 @@ struct ext2_super_block {
unsigned short s_max_mnt_count; /* Maximal mount count */ unsigned short s_max_mnt_count; /* Maximal mount count */
unsigned short s_magic; /* Magic signature */ unsigned short s_magic; /* Magic signature */
unsigned short s_state; /* File system state */ unsigned short s_state; /* File system state */
unsigned long s_reserved[241]; /* Padding to the end of the block */ unsigned short s_errors; /* Behaviour when detecting errors */
unsigned short s_pad;
unsigned long s_reserved[240]; /* Padding to the end of the block */
}; };
/* /*
...@@ -300,12 +324,28 @@ struct ext2_dir_entry { ...@@ -300,12 +324,28 @@ struct ext2_dir_entry {
* Function prototypes * Function prototypes
*/ */
/*
* Ok, these declarations are also in <linux/kernel.h> but none of the
* ext2 source programs needs to include it so they are duplicated here.
*/
#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5)
# define NORET_TYPE __volatile__
# define ATTRIB_NORET /**/
# define NORET_AND /**/
#else
# define NORET_TYPE /**/
# define ATTRIB_NORET __attribute__((noreturn))
# define NORET_AND noreturn,
#endif
/* acl.c */ /* acl.c */
extern int ext2_permission (struct inode *, int); extern int ext2_permission (struct inode *, int);
/* balloc.c */ /* balloc.c */
extern int ext2_new_block (struct super_block *, unsigned long); extern int ext2_new_block (struct super_block *, unsigned long,
extern void ext2_free_block (struct super_block *, unsigned long); unsigned long *, unsigned long *);
extern void ext2_free_blocks (struct super_block *, unsigned long,
unsigned long);
extern unsigned long ext2_count_free_blocks (struct super_block *); extern unsigned long ext2_count_free_blocks (struct super_block *);
extern void ext2_check_blocks_bitmap (struct super_block *); extern void ext2_check_blocks_bitmap (struct super_block *);
...@@ -351,6 +391,7 @@ extern void ext2_read_inode (struct inode *); ...@@ -351,6 +391,7 @@ extern void ext2_read_inode (struct inode *);
extern void ext2_write_inode (struct inode *); extern void ext2_write_inode (struct inode *);
extern void ext2_put_inode (struct inode *); extern void ext2_put_inode (struct inode *);
extern int ext2_sync_inode (struct inode *); extern int ext2_sync_inode (struct inode *);
extern void ext2_discard_prealloc (struct inode *);
/* ioctl.c */ /* ioctl.c */
extern int ext2_ioctl (struct inode *, struct file *, unsigned int, extern int ext2_ioctl (struct inode *, struct file *, unsigned int,
...@@ -374,14 +415,14 @@ extern int ext2_rename (struct inode *, const char *, int, ...@@ -374,14 +415,14 @@ extern int ext2_rename (struct inode *, const char *, int,
/* super.c */ /* super.c */
extern void ext2_error (struct super_block *, const char *, const char *, ...) extern void ext2_error (struct super_block *, const char *, const char *, ...)
__attribute__ ((format (printf, 3, 4))); __attribute__ ((format (printf, 3, 4)));
extern volatile void ext2_panic (struct super_block *, const char *, extern NORET_TYPE void ext2_panic (struct super_block *, const char *,
const char *, ...) const char *, ...)
__attribute__ ((format (printf, 3, 4))); __attribute__ ((NORET_AND format (printf, 3, 4)));
extern void ext2_warning (struct super_block *, const char *, const char *, ...) extern void ext2_warning (struct super_block *, const char *, const char *, ...)
__attribute__ ((format (printf, 3, 4))); __attribute__ ((format (printf, 3, 4)));
extern void ext2_put_super (struct super_block *); extern void ext2_put_super (struct super_block *);
extern void ext2_write_super (struct super_block *); extern void ext2_write_super (struct super_block *);
extern int ext2_remount (struct super_block *, int *); extern int ext2_remount (struct super_block *, int *, char *);
extern struct super_block * ext2_read_super (struct super_block *,void *,int); extern struct super_block * ext2_read_super (struct super_block *,void *,int);
extern void ext2_statfs (struct super_block *, struct statfs *); extern void ext2_statfs (struct super_block *, struct statfs *);
......
/* /*
* linux/include/linux/ext2_fs_i.h * linux/include/linux/ext2_fs_i.h
* *
* Copyright (C) 1992, 1993 Remy Card (card@masi.ibp.fr) * Copyright (C) 1992, 1993, 1994 Remy Card (card@masi.ibp.fr)
* Laboratoire MASI - Institut Blaise Pascal
* Universite Pierre et Marie Curie (Paris VI)
* *
* from * from
* *
...@@ -30,6 +32,8 @@ struct ext2_inode_info { ...@@ -30,6 +32,8 @@ struct ext2_inode_info {
unsigned long i_block_group; unsigned long i_block_group;
unsigned long i_next_alloc_block; unsigned long i_next_alloc_block;
unsigned long i_next_alloc_goal; unsigned long i_next_alloc_goal;
unsigned long i_prealloc_block;
unsigned long i_prealloc_count;
}; };
#endif /* _LINUX_EXT2_FS_I */ #endif /* _LINUX_EXT2_FS_I */
/* /*
* linux/include/linux/ext2_fs_sb.h * linux/include/linux/ext2_fs_sb.h
* *
* Copyright (C) 1992, 1993 Remy Card (card@masi.ibp.fr) * Copyright (C) 1992, 1993, 1994 Remy Card (card@masi.ibp.fr)
* Laboratoire MASI - Institut Blaise Pascal
* Universite Pierre et Marie Curie (Paris VI)
* *
* from * from
* *
...@@ -26,6 +28,7 @@ struct ext2_sb_info { ...@@ -26,6 +28,7 @@ struct ext2_sb_info {
unsigned long s_frags_per_group;/* Number of fragments in a group */ unsigned long s_frags_per_group;/* Number of fragments in a group */
unsigned long s_blocks_per_group;/* Number of blocks in a group */ unsigned long s_blocks_per_group;/* Number of blocks in a group */
unsigned long s_inodes_per_group;/* Number of inodes in a group */ unsigned long s_inodes_per_group;/* Number of inodes in a group */
unsigned long s_itb_per_group; /* Number of inode table blocks per group */
unsigned long s_desc_per_block; /* Number of group descriptors per block */ unsigned long s_desc_per_block; /* Number of group descriptors per block */
unsigned long s_groups_count; /* Number of groups in the fs */ unsigned long s_groups_count; /* Number of groups in the fs */
struct buffer_head * s_sbh; /* Buffer containing the super block */ struct buffer_head * s_sbh; /* Buffer containing the super block */
......
...@@ -300,7 +300,7 @@ struct super_operations { ...@@ -300,7 +300,7 @@ struct super_operations {
void (*put_super) (struct super_block *); void (*put_super) (struct super_block *);
void (*write_super) (struct super_block *); void (*write_super) (struct super_block *);
void (*statfs) (struct super_block *, struct statfs *); void (*statfs) (struct super_block *, struct statfs *);
int (*remount_fs) (struct super_block *, int *); int (*remount_fs) (struct super_block *, int *, char *);
}; };
struct file_system_type { struct file_system_type {
......
...@@ -49,7 +49,7 @@ typedef enum { ...@@ -49,7 +49,7 @@ typedef enum {
SS_UNCONNECTED, /* unconnected to any socket */ SS_UNCONNECTED, /* unconnected to any socket */
SS_CONNECTING, /* in process of connecting */ SS_CONNECTING, /* in process of connecting */
SS_CONNECTED, /* connected to socket */ SS_CONNECTED, /* connected to socket */
SS_DISCONNECTING, /* in process of disconnecting */ SS_DISCONNECTING /* in process of disconnecting */
} socket_state; } socket_state;
#define SO_ACCEPTCON (1<<16) /* performed a listen */ #define SO_ACCEPTCON (1<<16) /* performed a listen */
......
...@@ -25,17 +25,17 @@ ...@@ -25,17 +25,17 @@
enum rpc_auth_flavor { enum rpc_auth_flavor {
RPC_AUTH_NULL = 0, RPC_AUTH_NULL = 0,
RPC_AUTH_UNIX = 1, RPC_AUTH_UNIX = 1,
RPC_AUTH_SHORT = 2, RPC_AUTH_SHORT = 2
}; };
enum rpc_msg_type { enum rpc_msg_type {
RPC_CALL = 0, RPC_CALL = 0,
RPC_REPLY = 1, RPC_REPLY = 1
}; };
enum rpc_reply_stat { enum rpc_reply_stat {
RPC_MSG_ACCEPTED = 0, RPC_MSG_ACCEPTED = 0,
RPC_MSG_DENIED = 1, RPC_MSG_DENIED = 1
}; };
enum rpc_accept_stat { enum rpc_accept_stat {
...@@ -43,12 +43,12 @@ enum rpc_accept_stat { ...@@ -43,12 +43,12 @@ enum rpc_accept_stat {
RPC_PROG_UNAVAIL = 1, RPC_PROG_UNAVAIL = 1,
RPC_PROG_MISMATCH = 2, RPC_PROG_MISMATCH = 2,
RPC_PROC_UNAVAIL = 3, RPC_PROC_UNAVAIL = 3,
RPC_GARBAGE_ARGS = 4, RPC_GARBAGE_ARGS = 4
}; };
enum rpc_reject_stat { enum rpc_reject_stat {
RPC_MISMATCH = 0, RPC_MISMATCH = 0,
RPC_AUTH_ERROR = 1, RPC_AUTH_ERROR = 1
}; };
enum rpc_auth_stat { enum rpc_auth_stat {
...@@ -56,7 +56,7 @@ enum rpc_auth_stat { ...@@ -56,7 +56,7 @@ enum rpc_auth_stat {
RPC_AUTH_REJECTEDCRED = 2, RPC_AUTH_REJECTEDCRED = 2,
RPC_AUTH_BADVERF = 3, RPC_AUTH_BADVERF = 3,
RPC_AUTH_REJECTEDVERF = 4, RPC_AUTH_REJECTEDVERF = 4,
RPC_AUTH_TOOWEAK = 5, RPC_AUTH_TOOWEAK = 5
}; };
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
...@@ -80,7 +80,7 @@ enum nfs_stat { ...@@ -80,7 +80,7 @@ enum nfs_stat {
NFSERR_NOTEMPTY = 66, NFSERR_NOTEMPTY = 66,
NFSERR_DQUOT = 69, NFSERR_DQUOT = 69,
NFSERR_STALE = 70, NFSERR_STALE = 70,
NFSERR_WFLUSH = 99, NFSERR_WFLUSH = 99
}; };
enum nfs_ftype { enum nfs_ftype {
...@@ -92,7 +92,7 @@ enum nfs_ftype { ...@@ -92,7 +92,7 @@ enum nfs_ftype {
NFLNK = 5, NFLNK = 5,
NFSOCK = 6, NFSOCK = 6,
NFBAD = 7, NFBAD = 7,
NFFIFO = 8, NFFIFO = 8
}; };
#define NFS_PROGRAM 100003 #define NFS_PROGRAM 100003
......
...@@ -28,7 +28,7 @@ struct ip_config { ...@@ -28,7 +28,7 @@ struct ip_config {
unsigned long paddr; unsigned long paddr;
unsigned long router; unsigned long router;
unsigned long net; unsigned long net;
unsigned long up:1,destroy:1; unsigned int up:1,destroy:1;
}; };
#endif /* FIXME: */ #endif /* FIXME: */
......
...@@ -170,7 +170,6 @@ rt_add(short flags, unsigned long dst, unsigned long gw, struct device *dev) ...@@ -170,7 +170,6 @@ rt_add(short flags, unsigned long dst, unsigned long gw, struct device *dev)
} else { } else {
if (!((dst ^ dev->pa_addr) & dev->pa_mask)) { if (!((dst ^ dev->pa_addr) & dev->pa_mask)) {
mask = dev->pa_mask; mask = dev->pa_mask;
dst &= mask;
flags &= ~RTF_GATEWAY; flags &= ~RTF_GATEWAY;
if (flags & RTF_DYNAMIC) { if (flags & RTF_DYNAMIC) {
/*printk("Dynamic route to my own net rejected\n");*/ /*printk("Dynamic route to my own net rejected\n");*/
...@@ -178,6 +177,7 @@ rt_add(short flags, unsigned long dst, unsigned long gw, struct device *dev) ...@@ -178,6 +177,7 @@ rt_add(short flags, unsigned long dst, unsigned long gw, struct device *dev)
} }
} else } else
mask = guess_mask(dst); mask = guess_mask(dst);
dst &= mask;
} }
if (gw == dev->pa_addr) if (gw == dev->pa_addr)
flags &= ~RTF_GATEWAY; flags &= ~RTF_GATEWAY;
......
...@@ -18,5 +18,4 @@ struct new_utsname system_utsname = { ...@@ -18,5 +18,4 @@ struct new_utsname system_utsname = {
char *linux_banner = char *linux_banner =
"Linux version " UTS_RELEASE " (" LINUX_COMPILE_BY "@" "Linux version " UTS_RELEASE " (" LINUX_COMPILE_BY "@"
LINUX_COMPILE_HOST "." LINUX_COMPILE_DOMAIN ") " LINUX_COMPILE_HOST ") " UTS_VERSION "\n";
UTS_VERSION ": " LINUX_COMPILE_TIME "\n";
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment