VERSION = 0.99
PATCHLEVEL = 14
-ALPHA = i
+ALPHA = j
all: Version zImage
#
#
-VERSION = 2.3
+VERSION = 2.3b
TARGET_OS = linux
.c.s:
{
DEB(printk("dsp_set_stereo(%d)\n",mode));
- if (mode) dsp_stereo=mode;
+ dsp_stereo=mode;
return mode;
}
/*
* 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)
*/
/*
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/ext2_fs.h>
-#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/stat.h>
{
unsigned short mode = inode->i_mode;
- /* Special case, access is always granted for root */
+ /*
+ * Special case, access is always granted for root
+ */
if (suser ())
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)
mode >>= 6;
else if (in_group_p (inode->i_gid))
/*
* 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
*/
-/* 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
- 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 free blocks count in the block. The descriptors are loaded in memory
- when a file system is mounted (see ext2_read_super).
-
-*/
+/*
+ * The free blocks are managed by bitmaps. A file system contains several
+ * 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 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/ext2_fs.h>
-#include <linux/kernel.h>
#include <linux/stat.h>
#include <linux/sched.h>
#include <linux/string.h>
:"a" (0), "c" (size / 4), "D" ((long) (addr)) \
:"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)
{
int res;
int set = 0, bit = offset & 31, res;
if (bit) {
- /* Look for zero in first byte */
+ /*
+ * Look for zero in first byte
+ */
__asm__("
bsfl %1,%0
jne 1f
set = 32 - bit;
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));
return (offset + set + res);
}
return res;
}
-static void read_block_bitmap (struct super_block * sb,
- unsigned int block_group,
- unsigned long bitmap_nr)
+static struct ext2_group_desc * get_group_desc (struct super_block * sb,
+ unsigned int block_group,
+ struct buffer_head ** bh)
{
unsigned long group_desc;
unsigned long desc;
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);
desc = block_group % EXT2_DESC_PER_BLOCK(sb);
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"
"block_group = %d, group_desc = %lu, desc = %lu",
block_group, group_desc, desc);
gdp = (struct ext2_group_desc *)
- sb->u.ext2_sb.s_group_desc[group_desc]->b_data;
- bh = bread (sb->s_dev, gdp[desc].bg_block_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_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)
ext2_panic (sb, "read_block_bitmap",
"Cannot read block bitmap\n"
- "block_group = %d, group_desc = %lu,"
- "desc = %lu, block_bitmap = %lu",
- block_group, group_desc, desc,
- gdp[desc].bg_block_bitmap);
+ "block_group = %d, block_bitmap = %lu",
+ block_group, gdp->bg_block_bitmap);
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_number[0] = block_bitmap_number;
sb->u.ext2_sb.s_block_bitmap[0] = block_bitmap;
} else {
- if (sb->u.ext2_sb.s_loaded_block_bitmaps <
- EXT2_MAX_GROUP_LOADED)
+ if (sb->u.ext2_sb.s_loaded_block_bitmaps < EXT2_MAX_GROUP_LOADED)
sb->u.ext2_sb.s_loaded_block_bitmaps++;
else
- brelse (sb->u.ext2_sb.s_block_bitmap
- [EXT2_MAX_GROUP_LOADED - 1]);
+ brelse (sb->u.ext2_sb.s_block_bitmap[EXT2_MAX_GROUP_LOADED - 1]);
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 - 1];
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 * bh2;
unsigned long block_group;
unsigned long bit;
- unsigned long group_desc;
- unsigned long desc;
+ unsigned long i;
int bitmap_nr;
struct ext2_group_desc * gdp;
struct ext2_super_block * es;
if (!sb) {
- printk ("ext2_free_block: nonexistent device");
+ printk ("ext2_free_blocks: nonexistent device");
return;
}
lock_super (sb);
es = sb->u.ext2_sb.s_es;
- if (block < es->s_first_data_block || block >= es->s_blocks_count) {
- ext2_error (sb, "ext2_free_block", "block not in datazone");
+ if (block < es->s_first_data_block ||
+ (block + count) > es->s_blocks_count) {
+ ext2_error (sb, "ext2_free_blocks",
+ "Freeing blocks not in datazone");
unlock_super (sb);
return;
}
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) /
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);
bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr];
- if (!bh)
- ext2_panic (sb, "ext2_free_block",
- "Unable to load group bitmap\n"
- "block_group = %lu", block_group);
- if (!clear_bit (bit, bh->b_data))
- ext2_warning (sb, "ext2_free_block",
- "bit already cleared for block %lu", block);
- else {
- group_desc = block_group / EXT2_DESC_PER_BLOCK(sb);
- desc = block_group % EXT2_DESC_PER_BLOCK(sb);
- bh2 = sb->u.ext2_sb.s_group_desc[group_desc];
- if (!bh2)
- ext2_panic (sb, "ext2_free_block",
- "Group descriptor not loaded\n"
- "group_desc = %lu", group_desc);
- gdp = (struct ext2_group_desc *) bh2->b_data;
- gdp[desc].bg_free_blocks_count++;
- bh2->b_dirt = 1;
- es->s_free_blocks_count++;
- sb->u.ext2_sb.s_sbh->b_dirt = 1;
+ gdp = get_group_desc (sb, block_group, &bh2);
+
+ if (test_opt (sb, CHECK_STRICT) &&
+ (in_range (gdp->bg_block_bitmap, block, count) ||
+ in_range (gdp->bg_inode_bitmap, block, count) ||
+ in_range (block, gdp->bg_inode_table,
+ sb->u.ext2_sb.s_itb_per_group) ||
+ in_range (block + count - 1, gdp->bg_inode_table,
+ sb->u.ext2_sb.s_itb_per_group)))
+ ext2_panic (sb, "ext2_free_blocks",
+ "Freeing blocks in system zones\n"
+ "Block = %lu, count = %lu",
+ block, count);
+
+ for (i = 0; i < count; i++) {
+ if (!clear_bit (bit + i, bh->b_data))
+ ext2_warning (sb, "ext2_free_blocks",
+ "bit already cleared for block %lu",
+ block);
}
+
+ gdp->bg_free_blocks_count += count;
+ bh2->b_dirt = 1;
+ es->s_free_blocks_count += count;
+ sb->u.ext2_sb.s_sbh->b_dirt = 1;
+
bh->b_dirt = 1;
if (sb->s_flags & MS_SYNC) {
ll_rw_block (WRITE, 1, &bh);
* 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.
*/
-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;
- char *p, *r;
- int i, j, k;
+ struct buffer_head * bh2;
+ char * p, * r;
+ int i, j, k, tmp;
unsigned long lmap;
- unsigned long group_desc;
- unsigned long desc;
int bitmap_nr;
struct ext2_group_desc * gdp;
struct ext2_super_block * es;
ext2_debug ("goal=%lu.\n", goal);
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));
- group_desc = i / EXT2_DESC_PER_BLOCK(sb);
- desc = i % EXT2_DESC_PER_BLOCK(sb);
- 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) {
- j = ((goal - es->s_first_data_block) %
- EXT2_BLOCKS_PER_GROUP(sb));
+ gdp = get_group_desc (sb, i, &bh2);
+ if (gdp->bg_free_blocks_count > 0) {
+ j = ((goal - es->s_first_data_block) % EXT2_BLOCKS_PER_GROUP(sb));
#ifdef EXT2FS_DEBUG
if (j)
goal_attempts++;
#endif
bitmap_nr = load_block_bitmap (sb, i);
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,
- desc, j);
+ ext2_debug ("goal is at %d:%d.\n", i, j);
if (!test_bit(j, bh->b_data)) {
#ifdef EXT2FS_DEBUG
goto got_block;
}
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]) >>
((j & 31) + 1));
if (j < EXT2_BLOCKS_PER_GROUP(sb) - 32)
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,
- 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. */
+ /*
+ * There has been no free block found in the near vicinity
+ * of the goal: do a search forward through the block groups,
+ * 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.
+ */
p = ((char *) bh->b_data) + (j >> 3);
r = find_first_zero_byte (p,
(EXT2_BLOCKS_PER_GROUP(sb) - j + 7) >> 3);
k = (r - ((char *) bh->b_data)) << 3;
if (k < EXT2_BLOCKS_PER_GROUP(sb)) {
j = k;
- goto got_block;
+ goto search_back;
}
k = find_next_zero_bit ((unsigned long *) bh->b_data,
EXT2_BLOCKS_PER_GROUP(sb),
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++) {
i++;
- if (i >= sb->u.ext2_sb.s_groups_count) {
+ if (i >= sb->u.ext2_sb.s_groups_count)
i = 0;
- group_desc = 0;
- desc = 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)
+ gdp = get_group_desc (sb, i, &bh2);
+ if (gdp->bg_free_blocks_count > 0)
break;
}
if (k >= sb->u.ext2_sb.s_groups_count) {
}
bitmap_nr = load_block_bitmap (sb, i);
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,
EXT2_BLOCKS_PER_GROUP(sb) >> 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,
EXT2_BLOCKS_PER_GROUP(sb));
if (j >= EXT2_BLOCKS_PER_GROUP(sb)) {
unlock_super (sb);
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:
- ext2_debug ("using block group %d(%lu,%lu,%d)\n",
- i, group_desc, desc, gdp[desc].bg_free_blocks_count);
+ ext2_debug ("using block group %d(%d)\n", i, gdp->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)) {
ext2_warning (sb, "ext2_new_block",
"bit already set for block %d", j);
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;
if (sb->s_flags & MS_SYNC) {
ll_rw_block (WRITE, 1, &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) {
ext2_error (sb, "ext2_new_block",
"block >= blocks count\n"
ext2_debug ("allocating block %d. "
"Goal hits %d of %d.\n", j, goal_hits, goal_attempts);
- gdp[desc].bg_free_blocks_count--;
- sb->u.ext2_sb.s_group_desc[group_desc]->b_dirt = 1;
+ gdp->bg_free_blocks_count--;
+ bh2->b_dirt = 1;
es->s_free_blocks_count--;
sb->u.ext2_sb.s_sbh->b_dirt = 1;
sb->s_dirt = 1;
#ifdef EXT2FS_DEBUG
struct ext2_super_block * es;
unsigned long desc_count, bitmap_count, x;
- unsigned long group_desc;
- unsigned long desc;
int bitmap_nr;
struct ext2_group_desc * gdp;
int i;
es = sb->u.ext2_sb.s_es;
desc_count = 0;
bitmap_count = 0;
- group_desc = 0;
- desc = 0;
gdp = NULL;
for (i = 0; i < sb->u.ext2_sb.s_groups_count; i++) {
- if (!gdp) {
- if (!sb->u.ext2_sb.s_group_desc[group_desc]) {
- 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;
+ gdp = get_group_desc (sb, i, NULL);
+ desc_count += gdp->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;
- printk ("Cannot load bitmap for group %d\n", i);
- }
+ x = ext2_count_free (sb->u.ext2_sb.s_block_bitmap[bitmap_nr],
+ sb->s_blocksize);
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;
- 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",
es->s_free_blocks_count, desc_count, bitmap_count);
#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)
{
+ struct buffer_head * bh;
struct ext2_super_block * es;
unsigned long desc_count, bitmap_count, x;
- unsigned long group_desc;
- unsigned long desc;
int bitmap_nr;
struct ext2_group_desc * gdp;
- int i;
-
+ int i, j;
+
lock_super (sb);
es = sb->u.ext2_sb.s_es;
desc_count = 0;
bitmap_count = 0;
- group_desc = 0;
- desc = 0;
gdp = NULL;
for (i = 0; i < sb->u.ext2_sb.s_groups_count; i++) {
- if (!gdp) {
- if (!sb->u.ext2_sb.s_group_desc[group_desc]) {
- ext2_error (sb, "ext2_check_blocks_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_blocks_count;
+ gdp = get_group_desc (sb, i, NULL);
+ desc_count += gdp->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;
+ 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",
- "Cannot load bitmap for group %d\n", i);
- }
- if (gdp[desc].bg_free_blocks_count != x)
+ "Block bitmap for group %d is marked free",
+ i);
+
+ if (!block_in_use (gdp->bg_inode_bitmap, sb, bh->b_data))
+ ext2_error (sb, "ext2_check_blocks_bitmap",
+ "Inode bitmap for group %d is marked free",
+ i);
+
+ 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",
"Wrong free blocks count for group %d, "
"stored = %d, counted = %lu", i,
- gdp[desc].bg_free_blocks_count, x);
+ gdp->bg_free_blocks_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)
ext2_error (sb, "ext2_check_blocks_bitmap",
/*
* 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>
/*
* 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)
*
*/
#include <linux/fs.h>
#include <linux/ext2_fs.h>
-#include <linux/kernel.h>
#include <linux/string.h>
#ifndef DONT_USE_DCACHE
/*
* 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
*
#include <asm/segment.h>
+#include <linux/autoconf.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/ext2_fs.h>
#include <linux/sched.h>
#include <linux/stat.h>
-#if 0
+#ifndef CONFIG_EXT2_FS_DIR_READ
static int ext2_dir_read (struct inode * inode, struct file * filp,
char * buf, int count)
{
return -EISDIR;
}
+#else
+int ext2_file_read (struct inode *, struct file *, char *, int);
#endif
-/* static */ int ext2_file_read (struct inode *, struct file *, char *, int);
static int ext2_readdir (struct inode *, struct file *, struct dirent *, int);
static struct file_operations ext2_dir_operations = {
NULL, /* lseek - default */
+#ifdef CONFIG_EXT2_FS_DIR_READ
ext2_file_read, /* read */
+#else
+ ext2_dir_read, /* read */
+#endif
NULL, /* write - bad */
ext2_readdir, /* readdir */
NULL, /* select - default */
static int ext2_readdir (struct inode * inode, struct file * filp,
struct dirent * dirent, int count)
{
- unsigned long offset;
- int i;
- struct buffer_head * bh;
+ unsigned long offset, blk;
+ int i, num;
+ struct buffer_head * bh, * tmp, * bha[16];
struct ext2_dir_entry * de;
struct super_block * sb;
int err;
sb = inode->i_sb;
while (filp->f_pos < inode->i_size) {
offset = filp->f_pos & (sb->s_blocksize - 1);
- bh = ext2_bread (inode, (filp->f_pos) >> EXT2_BLOCK_SIZE_BITS(sb),
- 0, &err);
+ blk = (filp->f_pos) >> EXT2_BLOCK_SIZE_BITS(sb);
+ bh = ext2_bread (inode, blk, 0, &err);
if (!bh) {
filp->f_pos += sb->s_blocksize - offset;
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);
while (offset < sb->s_blocksize && filp->f_pos < inode->i_size) {
- if (! ext2_check_dir_entry ("ext2_readdir", inode, de,
- bh, offset)) {
+ if (!ext2_check_dir_entry ("ext2_readdir", inode, de,
+ bh, offset)) {
brelse (bh);
return 0;
}
/*
* 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
*
#include <asm/segment.h>
#include <asm/system.h>
+#include <linux/autoconf.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/ext2_fs.h>
#include <linux/fcntl.h>
-#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/stat.h>
#include <linux/locks.h>
#include <linux/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 void ext2_release_file (struct inode *, struct file *);
/*
* We have mostly NULL's here: the current defaults are ok for
ext2_ioctl, /* ioctl */
generic_mmap, /* mmap */
NULL, /* no special open is needed */
- NULL, /* release */
+ ext2_release_file, /* release */
ext2_sync_file /* fsync */
};
ext2_permission /* permission */
};
-/* static */ int ext2_file_read (struct inode * inode, struct file * filp,
- char * buf, int count)
+#ifndef CONFIG_EXT2_FS_DIR_READ
+static
+#endif
+int ext2_file_read (struct inode * inode, struct file * filp,
+ char * buf, int count)
{
int read, left, chars;
int block, blocks, offset;
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
- complete, and then we try and wrap up as many as are actually
- done. This routine is rather generic, in that it can be used
- 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. */
+ /*
+ * 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
+ * complete, and then we try and wrap up as many as are actually
+ * done. This routine is rather generic, in that it can be used
+ * 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.
+ */
do {
bhrequest = 0;
if (++bhb == &buflist[NBUF])
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)
break;
break;
}
- /* Now request them all */
+ /*
+ * Now request them all
+ */
if (bhrequest)
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) {
wait_on_buffer (*bhe);
if (!(*bhe)->b_uptodate) { /* read error? */
} while (left > 0 && bhe != bhb && (!*bhe || !(*bhe)->b_lock));
} while (left > 0);
- /* Release the read-ahead blocks */
+ /*
+ * Release the read-ahead blocks
+ */
while (bhe != bhb) {
brelse (*bhe);
if (++bhe == &buflist[NBUF])
return -EINVAL;
}
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)) {
ext2_warning (sb, "ext2_file_write", "mode = %07o\n",
inode->i_mode);
inode->i_dirt = 1;
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);
+}
* Copyright (C) 1993 Stephen Tweedie (sct@dcs.ed.ac.uk)
* from
* Copyright (C) 1992 Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
* from
* linux/fs/minix/truncate.c Copyright (C) 1991, 1992 Linus Torvalds
*
if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
S_ISLNK(inode->i_mode)))
return -EINVAL;
- /* Don't sync fast links! */
if (S_ISLNK(inode->i_mode) && !(inode->i_blocks))
+ /*
+ * Don't sync fast links!
+ */
goto skip;
for (wait=0; wait<=1; wait++)
-
/*
* 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
* 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
- 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 free blocks count in the block. The descriptors are loaded in memory
- when a file system is mounted (see ext2_read_super).
-
-*/
+/*
+ * The free inodes are managed by bitmaps. A file system contains several
+ * 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 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/ext2_fs.h>
-#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/stat.h>
#include <linux/string.h>
return res;
}
-static void read_inode_bitmap (struct super_block * sb,
- unsigned long block_group,
- unsigned int bitmap_nr)
+static struct ext2_group_desc * get_group_desc (struct super_block * sb,
+ unsigned int block_group,
+ struct buffer_head ** bh)
{
unsigned long group_desc;
unsigned long desc;
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);
desc = block_group % EXT2_DESC_PER_BLOCK(sb);
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"
- "block_group = %lu, group_desc = %lu, desc = %lu",
- block_group, group_desc, desc);
- gdp = (struct ext2_group_desc *) sb->u.ext2_sb.s_group_desc[group_desc]->b_data;
- bh = bread (sb->s_dev, gdp[desc].bg_inode_bitmap, sb->s_blocksize);
+ "block_group = %d, group_desc = %lu, desc = %lu",
+ block_group, group_desc, desc);
+ gdp = (struct ext2_group_desc *)
+ 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)
ext2_panic (sb, "read_inode_bitmap", "Cannot read inode bitmap\n"
- "block_group = %lu, group_desc = %lu, desc = %lu, inode_bitmap = %lu",
- block_group, group_desc, desc, gdp[desc].bg_inode_bitmap);
+ "block_group = %lu, inode_bitmap = %lu",
+ 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[bitmap_nr] = bh;
}
* This may be used one day by an 'undelete' program
*/
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;
struct buffer_head * bh;
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_BLOCK(inode->i_sb));
bh = bread (inode->i_sb->s_dev, inode_block, inode->i_sb->s_blocksize);
struct buffer_head * bh2;
unsigned long block_group;
unsigned long bit;
- unsigned long group_desc;
- unsigned long desc;
int bitmap_nr;
struct ext2_group_desc * gdp;
struct ext2_super_block * es;
bit = (inode->i_ino - 1) % EXT2_INODES_PER_GROUP(sb);
bitmap_nr = load_inode_bitmap (sb, block_group);
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))
ext2_warning (sb, "ext2_free_inode",
"bit already cleared for inode %lu", inode->i_ino);
else {
- group_desc = block_group / EXT2_DESC_PER_BLOCK(sb);
- desc = block_group % EXT2_DESC_PER_BLOCK(sb);
- 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++;
+ gdp = get_group_desc (sb, block_group, &bh2);
+ gdp->bg_free_inodes_count++;
if (S_ISDIR(inode->i_mode))
- gdp[desc].bg_used_dirs_count--;
+ gdp->bg_used_dirs_count--;
bh2->b_dirt = 1;
es->s_free_inodes_count++;
sb->u.ext2_sb.s_sbh->b_dirt = 1;
- set_inode_dtime (inode, gdp, desc);
+ set_inode_dtime (inode, gdp);
}
bh->b_dirt = 1;
if (sb->s_flags & MS_SYNC) {
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
* a directory, then a forward search is made for a block group with both
{
struct super_block * sb;
struct buffer_head * bh;
+ struct buffer_head * bh2;
int i, j, avefreei;
struct inode * inode;
int bitmap_nr;
- struct ext2_group_desc * gdp, * tmp;
+ struct ext2_group_desc * gdp;
+ struct ext2_group_desc * tmp;
struct ext2_super_block * es;
if (!dir || !(inode = get_empty_inode ()))
/* I am not yet convinced that this next bit is necessary.
i = dir->u.ext2_i.i_block_group;
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) <
tmp->bg_free_inodes_count) {
gdp = tmp;
*/
if (!gdp) {
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 &&
tmp->bg_free_inodes_count >= avefreei) {
if (!gdp ||
- (tmp->bg_free_inodes_count >
- gdp->bg_free_inodes_count)) {
+ (tmp->bg_free_blocks_count >
+ gdp->bg_free_blocks_count)) {
i = j;
gdp = tmp;
}
}
}
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;
- tmp = get_group_desc (sb, i);
+ tmp = get_group_desc (sb, i, &bh2);
if (tmp->bg_free_inodes_count)
gdp = tmp;
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) {
i += j;
if (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) {
gdp = tmp;
break;
}
}
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;
for (j = 2; j < sb->u.ext2_sb.s_groups_count; j++) {
if (++i >= sb->u.ext2_sb.s_groups_count)
i = 0;
- tmp = get_group_desc (sb,i);
+ tmp = get_group_desc (sb, i, &bh2);
if (tmp->bg_free_inodes_count) {
gdp = tmp;
break;
}
}
}
-
+
if (!gdp) {
unlock_super (sb);
iput(inode);
}
bitmap_nr = load_inode_bitmap (sb, i);
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,
EXT2_INODES_PER_GROUP(sb))) <
EXT2_INODES_PER_GROUP(sb)) {
} else
goto repeat;
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",
- "inode > inodes count\n"
+ "reserved inode or inode > inodes count\n"
"block_group = %d,inode=%d", i, j);
unlock_super (sb);
iput (inode);
gdp->bg_free_inodes_count--;
if (S_ISDIR(mode))
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--;
sb->u.ext2_sb.s_sbh->b_dirt = 1;
sb->s_dirt = 1;
inode->i_nlink = 1;
inode->i_dev = sb->s_dev;
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_ino = j;
inode->i_blksize = sb->s_blocksize;
#ifdef EXT2FS_DEBUG
struct ext2_super_block * es;
unsigned long desc_count, bitmap_count, x;
- unsigned long group_desc;
- unsigned long desc;
int bitmap_nr;
struct ext2_group_desc * gdp;
int i;
es = sb->u.ext2_sb.s_es;
desc_count = 0;
bitmap_count = 0;
- group_desc = 0;
- desc = 0;
gdp = NULL;
for (i = 0; i < sb->u.ext2_sb.s_groups_count; i++) {
- if (!gdp) {
- if (!sb->u.ext2_sb.s_group_desc[group_desc]) {
- 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;
+ gdp = get_group_desc (sb, i, NULL);
+ desc_count += gdp->bg_free_inodes_count;
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],
- EXT2_INODES_PER_GROUP(sb) / 8);
- else {
- x = 0;
- printk ("Cannot load inode bitmap for group %d (bitmap = %d)\n",
- i, bitmap_nr);
- }
+ x = ext2_count_free (sb->u.ext2_sb.s_inode_bitmap[bitmap_nr],
+ EXT2_INODES_PER_GROUP(sb) / 8);
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;
- 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",
es->s_free_inodes_count, desc_count, bitmap_count);
{
struct ext2_super_block * es;
unsigned long desc_count, bitmap_count, x;
- unsigned long group_desc;
- unsigned long desc;
int bitmap_nr;
struct ext2_group_desc * gdp;
int i;
es = sb->u.ext2_sb.s_es;
desc_count = 0;
bitmap_count = 0;
- group_desc = 0;
- desc = 0;
gdp = NULL;
for (i = 0; i < sb->u.ext2_sb.s_groups_count; i++) {
- if (!gdp) {
- if (!sb->u.ext2_sb.s_group_desc[group_desc]) {
- 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;
+ gdp = get_group_desc (sb, i, NULL);
+ desc_count += gdp->bg_free_inodes_count;
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],
- EXT2_INODES_PER_GROUP(sb) / 8);
- else {
- 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)
+ x = ext2_count_free (sb->u.ext2_sb.s_inode_bitmap[bitmap_nr],
+ EXT2_INODES_PER_GROUP(sb) / 8);
+ if (gdp->bg_free_inodes_count != x)
ext2_error (sb, "ext2_check_inodes_bitmap",
"Wrong free inodes count in group %d, "
"stored = %d, counted = %lu", i,
- gdp[desc].bg_free_inodes_count, x);
+ gdp->bg_free_inodes_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)
ext2_error (sb, "ext2_check_inodes_bitmap",
/*
* 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
*
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/ext2_fs.h>
-#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/stat.h>
#include <linux/string.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)
{
+ ext2_discard_prealloc (inode);
if (inode->i_nlink || inode->i_ino == EXT2_ACL_IDX_INO ||
inode->i_ino == EXT2_ACL_DATA_INO)
return;
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 i;
ext2_debug ("goal = %d.\n", goal);
- tmp = ext2_new_block (inode->i_sb, goal);
+ tmp = ext2_alloc_block (inode, goal);
if (!tmp)
return NULL;
result = getblk (inode->i_dev, tmp, inode->i_sb->s_blocksize);
if (*p) {
- ext2_free_block (inode->i_sb, tmp);
+ ext2_free_blocks (inode->i_sb, tmp, 1);
brelse (result);
goto repeat;
}
if (!goal)
goal = bh->b_blocknr + 1;
}
- tmp = ext2_new_block (inode->i_sb, goal);
+ tmp = ext2_alloc_block (inode, goal);
if (!tmp) {
brelse (bh);
return NULL;
}
result = getblk (bh->b_dev, tmp, blocksize);
if (*p) {
- ext2_free_block (inode->i_sb, tmp);
+ ext2_free_blocks (inode->i_sb, tmp, 1);
brelse (result);
goto repeat;
}
ext2_warning (inode->i_sb, "ext2_getblk", "block > big");
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
- allocations use the same goal zone */
+ /*
+ * If this is a sequential block allocation, set the next_alloc_block
+ * 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,
inode->u.ext2_i.i_next_alloc_block,
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_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))
inode->i_rdev = raw_inode->i_block[0];
else for (block = 0; block < EXT2_N_BLOCKS; block++)
/*
* 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>
/*
* 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
*
#include <linux/fs.h>
#include <linux/ext2_fs.h>
#include <linux/fcntl.h>
-#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/stat.h>
#include <linux/string.h>
* truncated. Else they will be disallowed.
*/
/* #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.
*/
if (!de || !de->inode || len > EXT2_NAME_LEN)
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] == '.') &&
(de->name[1] == '\0'))
return 1;
* 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
* entry - you'll have to do that yourself if you want to.
- *
*/
static struct buffer_head * ext2_find_entry (struct inode * dir,
const char * const name, int namelen,
struct ext2_dir_entry ** res_dir)
{
- unsigned long offset;
- struct buffer_head * bh;
- struct ext2_dir_entry * de;
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;
if (!dir)
return NULL;
sb = dir->i_sb;
+
#ifdef NO_TRUNCATE
if (namelen > EXT2_NAME_LEN)
return NULL;
if (namelen > EXT2_NAME_LEN)
namelen = EXT2_NAME_LEN;
#endif
- bh = ext2_bread (dir, 0, 0, &err);
- if (!bh)
- return NULL;
+
+ memset (bh_use, 0, sizeof (bh_use));
+ 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;
- de = (struct ext2_dir_entry *) bh->b_data;
while (offset < dir->i_size) {
- if (!bh || (char *)de >= sb->s_blocksize + bh->b_data) {
- brelse (bh);
- bh = ext2_bread (dir, offset >> EXT2_BLOCK_SIZE_BITS(sb), 0, &err);
- if (!bh) {
- offset += sb->s_blocksize;
- continue;
- }
- de = (struct ext2_dir_entry *) bh->b_data;
+ struct buffer_head * bh;
+ struct ext2_dir_entry * de;
+ char * dlimit;
+
+ if ((block % NAMEI_RA_BLOCKS) == 0 && toread) {
+ ll_rw_block (READ, toread, bh_read);
+ toread = 0;
}
- if (! ext2_check_dir_entry ("ext2_find_entry", dir, de, bh,
- offset)) {
- brelse (bh);
- return NULL;
+ bh = bh_use[block % NAMEI_RA_SIZE];
+ if (!bh)
+ ext2_panic (sb, "ext2_find_entry",
+ "buffer head pointer is NULL");
+ wait_on_buffer (bh);
+ if (!bh->b_uptodate) {
+ /*
+ * read error: all bets are off
+ */
+ break;
}
- if (de->inode != 0 && ext2_match (namelen, name, de)) {
- *res_dir = de;
- return bh;
+
+ 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)) {
+ for (i = 0; i < NAMEI_RA_SIZE; ++i) {
+ if (bh_use[i] != bh)
+ brelse (bh_use[i]);
+ }
+ *res_dir = de;
+ return bh;
+ }
+ offset += de->rec_len;
+ de = (struct ext2_dir_entry *)
+ ((char *) de + de->rec_len);
}
- offset += de->rec_len;
- de = (struct ext2_dir_entry *) ((char *) de + de->rec_len);
+
+ 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;
}
- brelse (bh);
+
+failure:
+ for (i = 0; i < NAMEI_RA_SIZE; ++i)
+ brelse (bh_use[i]);
return NULL;
}
#endif
if (!namelen)
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)
{
*err = -ENOENT;
de = (struct ext2_dir_entry *) bh->b_data;
}
}
- if (! ext2_check_dir_entry ("ext2_add_entry", dir, de, bh,
- offset)) {
+ if (!ext2_check_dir_entry ("ext2_add_entry", dir, de, bh,
+ offset)) {
*err = -ENOENT;
brelse (bh);
return NULL;
pde = NULL;
de = (struct ext2_dir_entry *) bh->b_data;
while (i < bh->b_size) {
- if (! ext2_check_dir_entry ("ext2_delete_entry", NULL,
- de, bh, i))
+ if (!ext2_check_dir_entry ("ext2_delete_entry", NULL,
+ de, bh, i))
return -EIO;
if (de == dir) {
if (pde)
pde->rec_len += dir->rec_len;
- /* XXX - must zero the inode number in every case !! */
dir->inode = 0;
return 0;
}
}
de = (struct ext2_dir_entry *) bh->b_data;
}
- if (! ext2_check_dir_entry ("empty_dir", inode, de, bh,
- offset)) {
+ if (!ext2_check_dir_entry ("empty_dir", inode, de, bh,
+ offset)) {
brelse (bh);
return 1;
}
goto end_rmdir;
}
if (inode->i_count > 1) {
- /* Are we deleting the last instance of a busy directory?
- Better clean up if so. */
- /* Make directory empty (it will be truncated when finally
- dereferenced). This also inhibits ext2_add_entry. */
+ /*
+ * Are we deleting the last instance of a busy directory?
+ * Better clean up if so.
+ *
+ * Make directory empty (it will be truncated when finally
+ * dereferenced). This also inhibits ext2_add_entry.
+ */
inode->i_size = 0;
}
retval = ext2_delete_entry (de, bh);
&retval);
if (!new_bh)
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))
goto try_again;
if (new_de->inode && !new_inode)
goto try_again;
if (old_de->inode != old_inode->i_ino)
goto try_again;
-/* ok, that's it */
+ /*
+ * ok, that's it
+ */
new_de->inode = old_inode->i_ino;
#ifndef DONT_USE_DCACHE
ext2_dcache_remove (old_dir->i_dev, old_dir->i_ino, old_de->name,
/*
* 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
*
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/ext2_fs.h>
-#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/stat.h>
#include <linux/string.h>
va_start (args, fmt);
vsprintf (buf, fmt, args);
va_end (args);
- printk (
-#ifdef KERN_ERR
- KERN_ERR
-#endif
- "EXT2-fs error (device %d/%d): %s: %s\n",
+ if (test_opt (sb, ERRORS_PANIC) ||
+ (sb->u.ext2_sb.s_es->s_errors == EXT2_ERRORS_PANIC &&
+ !test_opt (sb, ERRORS_CONT) && !test_opt (sb, ERRORS_RO)))
+ panic ("EXT2-fs panic (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);
+ 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,
- const char * fmt, ...)
+NORET_TYPE void ext2_panic (struct super_block * sb, const char * function,
+ const char * fmt, ...)
{
char buf[1024];
va_list args;
va_start (args, fmt);
vsprintf (buf, fmt, args);
va_end (args);
- printk (
-#ifdef KERN_WARNING
- KERN_WARNING
-#endif
- "EXT2-fs warning (device %d/%d): %s: %s\n",
+ printk (KERN_WARNING "EXT2-fs warning (device %d/%d): %s: %s\n",
MAJOR(sb->s_dev), MINOR(sb->s_dev), function, buf);
}
this_char = strtok (NULL, ",")) {
if ((value = strchr (this_char, '=')) != NULL)
*value++ = 0;
- if (!strcmp (this_char, "check"))
- *mount_options |= EXT2_MOUNT_CHECK;
- else if (!strcmp (this_char, "sb")) {
+ if (!strcmp (this_char, "check")) {
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;
+ }
+ }
+ 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);
- if (*value)
+ if (*value) {
+ printk ("EXT2-fs: Invalid sb option: %s\n",
+ value);
return 0;
+ }
}
else {
printk ("EXT2-fs: Unrecognized mount option %s\n", this_char);
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)
{
struct buffer_head * bh;
struct ext2_super_block * es;
unsigned long sb_block = 1;
unsigned long logic_sb_block = 1;
- int dev = s->s_dev;
+ int dev = sb->s_dev;
int bh_count;
int i, j;
#ifdef EXT2FS_PRE_02B_COMPAT
int fs_converted = 0;
#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,
- &s->u.ext2_sb.s_mount_opt)) {
- s->s_dev = 0;
+ &sb->u.ext2_sb.s_mount_opt)) {
+ sb->s_dev = 0;
return NULL;
}
- lock_super (s);
+ lock_super (sb);
set_blocksize (dev, BLOCK_SIZE);
if (!(bh = bread (dev, sb_block, BLOCK_SIZE))) {
- s->s_dev = 0;
- unlock_super (s);
+ sb->s_dev = 0;
+ unlock_super (sb);
printk ("EXT2-fs: unable to read superblock\n");
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;
- /* Note: s_es must be initialized s_es as soon as possible because
- some ext2 macro-instructions depend on its value */
- s->u.ext2_sb.s_es = es;
- s->s_magic = es->s_magic;
- if (s->s_magic != EXT2_SUPER_MAGIC
+ sb->u.ext2_sb.s_es = es;
+ sb->s_magic = es->s_magic;
+ if (sb->s_magic != EXT2_SUPER_MAGIC
#ifdef EXT2FS_PRE_02B_COMPAT
- && s->s_magic != EXT2_PRE_02B_MAGIC
+ && sb->s_magic != EXT2_PRE_02B_MAGIC
#endif
) {
- s->s_dev = 0;
- unlock_super (s);
+ sb->s_dev = 0;
+ unlock_super (sb);
brelse (bh);
if (!silent)
printk ("VFS: Can't find an ext2 filesystem on dev 0x%04x.\n",
dev);
return NULL;
}
- s->s_blocksize = EXT2_MIN_BLOCK_SIZE << es->s_log_block_size;
- s->s_blocksize_bits = EXT2_BLOCK_SIZE_BITS(s);
- if (s->s_blocksize != BLOCK_SIZE &&
- (s->s_blocksize == 1024 || s->s_blocksize == 2048 ||
- s->s_blocksize == 4096)) {
+ sb->s_blocksize = EXT2_MIN_BLOCK_SIZE << es->s_log_block_size;
+ sb->s_blocksize_bits = EXT2_BLOCK_SIZE_BITS(sb);
+ if (sb->s_blocksize != BLOCK_SIZE &&
+ (sb->s_blocksize == 1024 || sb->s_blocksize == 2048 ||
+ sb->s_blocksize == 4096)) {
unsigned long offset;
brelse (bh);
- set_blocksize (dev, s->s_blocksize);
- logic_sb_block = sb_block / s->s_blocksize;
- offset = sb_block % s->s_blocksize;
- bh = bread (dev, logic_sb_block, s->s_blocksize);
+ set_blocksize (dev, sb->s_blocksize);
+ logic_sb_block = sb_block / sb->s_blocksize;
+ offset = sb_block % sb->s_blocksize;
+ bh = bread (dev, logic_sb_block, sb->s_blocksize);
if(!bh)
return NULL;
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) {
- s->s_dev = 0;
- unlock_super (s);
+ sb->s_dev = 0;
+ unlock_super (sb);
brelse (bh);
printk ("EXT2-fs: Magic mismatch, very weird !\n");
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;
- if (s->u.ext2_sb.s_frag_size)
- s->u.ext2_sb.s_frags_per_block = s->s_blocksize /
- s->u.ext2_sb.s_frag_size;
+ if (sb->u.ext2_sb.s_frag_size)
+ sb->u.ext2_sb.s_frags_per_block = sb->s_blocksize /
+ sb->u.ext2_sb.s_frag_size;
else
- s->s_magic = 0;
- s->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;
- s->u.ext2_sb.s_inodes_per_group = es->s_inodes_per_group;
- s->u.ext2_sb.s_inodes_per_block = s->s_blocksize /
- sizeof (struct ext2_inode);
- s->u.ext2_sb.s_desc_per_block = s->s_blocksize /
- sizeof (struct ext2_group_desc);
- s->u.ext2_sb.s_sbh = bh;
- s->u.ext2_sb.s_es = es;
- s->u.ext2_sb.s_mount_state = es->s_state;
- s->u.ext2_sb.s_rename_lock = 0;
- s->u.ext2_sb.s_rename_wait = NULL;
+ sb->s_magic = 0;
+ sb->u.ext2_sb.s_blocks_per_group = es->s_blocks_per_group;
+ sb->u.ext2_sb.s_frags_per_group = es->s_frags_per_group;
+ sb->u.ext2_sb.s_inodes_per_group = es->s_inodes_per_group;
+ sb->u.ext2_sb.s_inodes_per_block = sb->s_blocksize /
+ sizeof (struct ext2_inode);
+ 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);
+ sb->u.ext2_sb.s_sbh = bh;
+ sb->u.ext2_sb.s_es = es;
+ sb->u.ext2_sb.s_mount_state = es->s_state;
+ sb->u.ext2_sb.s_rename_lock = 0;
+ sb->u.ext2_sb.s_rename_wait = NULL;
#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) {
- /* fs > 256 MB can't be converted */
- s->s_dev = 0;
- unlock_super (s);
+ /*
+ * fs > 256 MB can't be converted
+ */
+ sb->s_dev = 0;
+ unlock_super (sb);
brelse (bh);
printk ("EXT2-fs: trying to mount a pre-0.2b file"
"system which cannot be converted\n");
}
printk ("EXT2-fs: mounting a pre 0.2b file system, "
"will try to convert the structure\n");
- if (!(s->s_flags & MS_RDONLY)) {
- s->s_dev = 0;
- unlock_super (s);
+ if (!(sb->s_flags & MS_RDONLY)) {
+ sb->s_dev = 0;
+ unlock_super (sb);
brelse (bh);
printk ("EXT2-fs: cannot convert a read-only fs\n");
return NULL;
}
- if (!convert_pre_02b_fs (s, bh)) {
- s->s_dev = 0;
- unlock_super (s);
+ if (!convert_pre_02b_fs (sb, bh)) {
+ sb->s_dev = 0;
+ unlock_super (sb);
brelse (bh);
printk ("EXT2-fs: conversion failed !!!\n");
return NULL;
fs_converted = 1;
}
#endif
- if (s->s_magic != EXT2_SUPER_MAGIC) {
- s->s_dev = 0;
- unlock_super (s);
+ if (sb->s_magic != EXT2_SUPER_MAGIC) {
+ sb->s_dev = 0;
+ unlock_super (sb);
brelse (bh);
if (!silent)
printk ("VFS: Can't find an ext2 filesystem on dev 0x%04x.\n",
dev);
return NULL;
}
- if (s->s_blocksize != bh->b_size) {
- s->s_dev = 0;
- unlock_super (s);
+ if (sb->s_blocksize != bh->b_size) {
+ sb->s_dev = 0;
+ unlock_super (sb);
brelse (bh);
if (!silent)
printk ("VFS: Unsupported blocksize on dev 0x%04x.\n",
return NULL;
}
- if (s->s_blocksize != s->u.ext2_sb.s_frag_size) {
- s->s_dev = 0;
- unlock_super (s);
+ if (sb->s_blocksize != sb->u.ext2_sb.s_frag_size) {
+ sb->s_dev = 0;
+ unlock_super (sb);
brelse (bh);
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;
}
- s->u.ext2_sb.s_groups_count = (es->s_blocks_count -
- es->s_first_data_block +
- EXT2_BLOCKS_PER_GROUP(s) - 1) /
- EXT2_BLOCKS_PER_GROUP(s);
+ sb->u.ext2_sb.s_groups_count = (es->s_blocks_count -
+ es->s_first_data_block +
+ EXT2_BLOCKS_PER_GROUP(sb) - 1) /
+ EXT2_BLOCKS_PER_GROUP(sb);
for (i = 0; i < EXT2_MAX_GROUP_DESC; i++)
- s->u.ext2_sb.s_group_desc[i] = NULL;
- bh_count = (s->u.ext2_sb.s_groups_count + EXT2_DESC_PER_BLOCK(s) - 1) /
- EXT2_DESC_PER_BLOCK(s);
+ sb->u.ext2_sb.s_group_desc[i] = NULL;
+ bh_count = (sb->u.ext2_sb.s_groups_count + EXT2_DESC_PER_BLOCK(sb) - 1) /
+ EXT2_DESC_PER_BLOCK(sb);
if (bh_count > EXT2_MAX_GROUP_DESC) {
- s->s_dev = 0;
- unlock_super (s);
+ sb->s_dev = 0;
+ unlock_super (sb);
brelse (bh);
printk ("EXT2-fs: file system is too big\n");
return NULL;
}
for (i = 0; i < bh_count; i++) {
- s->u.ext2_sb.s_group_desc[i] = bread (dev, logic_sb_block + i + 1,
- s->s_blocksize);
- if (!s->u.ext2_sb.s_group_desc[i]) {
- s->s_dev = 0;
- unlock_super (s);
+ sb->u.ext2_sb.s_group_desc[i] = bread (dev, logic_sb_block + i + 1,
+ sb->s_blocksize);
+ if (!sb->u.ext2_sb.s_group_desc[i]) {
+ sb->s_dev = 0;
+ unlock_super (sb);
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);
printk ("EXT2-fs: unable to read group descriptors\n");
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++) {
- s->u.ext2_sb.s_inode_bitmap_number[i] = 0;
- s->u.ext2_sb.s_inode_bitmap[i] = NULL;
- s->u.ext2_sb.s_block_bitmap_number[i] = 0;
- s->u.ext2_sb.s_block_bitmap[i] = NULL;
+ sb->u.ext2_sb.s_inode_bitmap_number[i] = 0;
+ sb->u.ext2_sb.s_inode_bitmap[i] = NULL;
+ sb->u.ext2_sb.s_block_bitmap_number[i] = 0;
+ sb->u.ext2_sb.s_block_bitmap[i] = NULL;
}
- s->u.ext2_sb.s_loaded_inode_bitmaps = 0;
- s->u.ext2_sb.s_loaded_block_bitmaps = 0;
- unlock_super (s);
- /* set up enough so that it can read an inode */
- s->s_dev = dev;
- s->s_op = &ext2_sops;
- if (!(s->s_mounted = iget (s, EXT2_ROOT_INO))) {
- s->s_dev = 0;
+ sb->u.ext2_sb.s_loaded_inode_bitmaps = 0;
+ sb->u.ext2_sb.s_loaded_block_bitmaps = 0;
+ unlock_super (sb);
+ /*
+ * set up enough so that it can read an inode
+ */
+ sb->s_dev = dev;
+ 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++)
- if (s->u.ext2_sb.s_group_desc[i])
- brelse (s->u.ext2_sb.s_group_desc[i]);
+ if (sb->u.ext2_sb.s_group_desc[i])
+ brelse (sb->u.ext2_sb.s_group_desc[i]);
brelse (bh);
printk ("EXT2-fs: get root inode failed\n");
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
if (fs_converted) {
for (i = 0; i < bh_count; i++)
- s->u.ext2_sb.s_group_desc[i]->b_dirt = 1;
- s->s_dirt = 1;
+ sb->u.ext2_sb.s_group_desc[i]->b_dirt = 1;
+ sb->s_dirt = 1;
}
#endif
- if (!(s->u.ext2_sb.s_mount_state & EXT2_VALID_FS))
- printk ("EXT2-fs warning: mounting unchecked file system, "
- "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;
+ ext2_setup_super (sb, es);
+ return sb;
}
static void ext2_commit_super (struct super_block * sb,
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;
+ 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;
if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY))
if (es->s_state & EXT2_VALID_FS ||
!(sb->u.ext2_sb.s_mount_state & EXT2_VALID_FS))
return 0;
- /* OK, we are remounting a valid rw partition rdonly, so set
- the rdonly flag and then mark the partition as valid
- again. */
+ /*
+ * OK, we are remounting a valid rw partition rdonly, so set
+ * the rdonly flag and then mark the partition as valid again.
+ */
es->s_state = sb->u.ext2_sb.s_mount_state;
es->s_mtime = CURRENT_TIME;
sb->u.ext2_sb.s_sbh->b_dirt = 1;
ext2_commit_super (sb, es);
}
else {
- /* Mounting a RDONLY partition read-write, so reread and
- store the current valid flag. (It may have been changed
- by e2fsck since we originally mounted the partition.) */
+ /*
+ * Mounting a RDONLY partition read-write, so reread and
+ * 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;
- 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 (!(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");
+ sb->s_flags &= ~MS_RDONLY;
+ ext2_setup_super (sb, es);
}
return 0;
}
/*
* 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
*
/*
* 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
*
bh->b_dirt = 1;
}
brelse (bh);
- ext2_free_block (inode->i_sb, tmp);
+ ext2_free_blocks (inode->i_sb, tmp, 1);
}
return retry;
}
bh->b_dirt = 1;
}
brelse (bh);
- ext2_free_block (inode->i_sb, tmp);
+ ext2_free_blocks (inode->i_sb, tmp, 1);
inode->i_blocks -= blocks;
inode->i_dirt = 1;
}
*p = 0;
inode->i_blocks -= blocks;
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) {
ll_rw_block (WRITE, 1, &ind_bh);
*p = 0;
inode->i_blocks -= blocks;
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) {
ll_rw_block (WRITE, 1, &dind_bh);
*p = 0;
inode->i_blocks -= blocks;
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) {
ll_rw_block (WRITE, 1, &tind_bh);
if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
S_ISLNK(inode->i_mode)))
return;
+ ext2_discard_prealloc(inode);
while (1) {
retry = trunc_direct(inode);
retry |= trunc_indirect (inode, EXT2_IND_BLOCK,
inode->i_mtime = inode->i_ctime = CURRENT_TIME;
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");
-}
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 */
dev_t ROOT_DEV = 0;
if (!(sb=get_super(dev)))
return -ENOENT;
if (!(sb->s_flags & MS_RDONLY)) {
- retval = do_remount_sb(sb, MS_RDONLY);
+ retval = do_remount_sb(sb, MS_RDONLY, 0);
if (retval)
return retval;
}
* 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;
if (!fs_may_remount_ro(sb->s_dev))
return -EBUSY;
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)
return retval;
}
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;
int retval;
iput(dir_i);
return -EINVAL;
}
- retval = do_remount_sb(dir_i->i_sb, flags);
+ retval = do_remount_sb(dir_i->i_sb, flags, data);
iput(dir_i);
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
* 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
- * can contain arbitrary fs-dependent information (or be NULL).
+ * data is a (void *) that can point to any structure up to
+ * 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
- * a special 16-bit magic number in the hight word: 0xC0ED. If this magic word
- * isn't present, the flags and data info isn't used, as the syscall assumes we
- * are talking to an older version that didn't understand them.
+ * NOTE! As old versions of mount() didn't use this setup, the flags
+ * has to have a special 16-bit magic number in the hight word:
+ * 0xC0ED. If this magic word isn't present, the flags and data info
+ * 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,
unsigned long new_flags, void * data)
struct file_operations * fops;
dev_t dev;
int retval;
- char tmp[100], * t;
- int i;
+ char * t;
unsigned long flags = 0;
unsigned long page = 0;
if (!suser())
return -EPERM;
- if ((new_flags & (MS_MGC_MSK | MS_REMOUNT)) == (MS_MGC_VAL | MS_REMOUNT)) {
- return do_remount(dir_name,new_flags & ~MS_MGC_MSK & ~MS_REMOUNT);
+ if ((new_flags &
+ (MS_MGC_MSK | MS_REMOUNT)) == (MS_MGC_VAL | MS_REMOUNT)) {
+ retval = copy_mount_options (data, &page);
+ if (retval < 0)
+ return retval;
+ retval = do_remount(dir_name,
+ new_flags & ~MS_MGC_MSK & ~MS_REMOUNT,
+ (char *) page);
+ free_page(page);
+ return retval;
}
- if (type) {
- for (i = 0 ; i < 100 ; i++) {
- if (TASK_SIZE <= (unsigned long) type)
- return -EFAULT;
- if (!(tmp[i] = get_fs_byte(type++)))
- break;
- }
- t = tmp;
- } else
- t = NULL;
- if (!(fstype = get_fs_type(t)))
+ retval = copy_mount_options (type, &page);
+ if (retval < 0)
+ return retval;
+ fstype = get_fs_type((char *) page);
+ free_page(page);
+ if (!fstype)
return -ENODEV;
t = fstype->name;
if (fstype->requires_dev) {
}
if ((new_flags & MS_MGC_MSK) == MS_MGC_VAL) {
flags = new_flags & ~MS_MGC_MSK;
- if (data) {
- struct vm_area_struct * vma;
-
- for (vma = current->mmap ; ; ) {
- if (!vma || (unsigned long) data < vma->vm_start) {
- iput(inode);
- 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))) {
- iput(inode);
- return -ENOMEM;
- }
- memcpy_fromfs((void *) page,data,i);
+ retval = copy_mount_options(data, &page);
+ if (retval < 0) {
+ iput(inode);
+ return retval;
}
}
retval = do_mount(dev,dir_name,t,flags,(void *) page);
* to guarantee better timings even on fast machines.
*
* 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
*/
#define SLOW_DOWN_IO __SLOW_DOWN_IO
#endif
-/* This is the more general version of outb.. */
-extern inline void __outb(unsigned char value, unsigned short port)
-{
-__asm__ __volatile__ ("outb %b0,%w1"
- : /* no outputs */
- :"a" (value),"d" (port));
-}
-
-/* this is used for constant port numbers < 256.. */
-extern inline void __outbc(unsigned char value, unsigned short port)
-{
-__asm__ __volatile__ ("outb %b0,%1"
- : /* no outputs */
- :"a" (value),"i" (port));
-}
-
-/* general version of inb */
-extern inline unsigned int __inb(unsigned short port)
-{
- unsigned int _v;
-__asm__ __volatile__ ("inb %w1,%b0"
- :"=a" (_v):"d" (port),"0" (0));
- return _v;
-}
-
-/* inb with constant port nr 0-255 */
-extern inline unsigned int __inbc(unsigned short port)
-{
- unsigned int _v;
-__asm__ __volatile__ ("inb %1,%b0"
- :"=a" (_v):"i" (port),"0" (0));
- return _v;
-}
-
-extern inline void __outb_p(unsigned char value, unsigned short port)
-{
-__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;
-}
+/*
+ * Talk about misusing macros..
+ */
+
+#define __OUT1(s,x) \
+extern inline void __out##s(unsigned x value, unsigned short port) {
+
+#define __OUT2(s,s1,s2) \
+__asm__ __volatile__ ("out" #s " %" s1 "0,%" s2 "1"
+
+#define __OUT(s,s1,x) \
+__OUT1(s,x) __OUT2(s,s1,"w") : : "a" (value), "d" (port)); } \
+__OUT1(s##c,x) __OUT2(s,s1,"") : : "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; }
+
+#define __IN1(s) \
+extern inline unsigned int __in##s(unsigned short port) { unsigned int _v;
+
+#define __IN2(s,s1,s2) \
+__asm__ __volatile__ ("in" #s " %" s2 "1,%" s1 "0"
+
+#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; } \
+__IN1(s##_p) __IN2(s,s1,"w") : "=a" (_v) : "d" (port) ,##i ); SLOW_DOWN_IO; return _v; } \
+__IN1(s##c_p) __IN2(s,s1,"") : "=a" (_v) : "i" (port) ,##i ); SLOW_DOWN_IO; return _v; }
+
+__IN(b,"b","0" (0))
+__IN(w,"w","0" (0))
+__IN(l,"")
+
+__OUT(b,"b",char)
+__OUT(w,"w",short)
+__OUT(l,,int)
/*
* Note that due to the way __builtin_constant_p() works, you
__inbc_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
"movl $" STR(USER_DS) ",%edx\n\t" \
"mov %dx,%fs\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,
/*
* 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
*
#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
*/
-#define EXT2FS_DATE "93/11/19"
-#define EXT2FS_VERSION "0.4a"
+#define EXT2FS_DATE "93/12/30"
+#define EXT2FS_VERSION "0.4b"
/*
* Debug code
/*
* 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
*/
#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
*/
unsigned short s_max_mnt_count; /* Maximal mount count */
unsigned short s_magic; /* Magic signature */
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 */
};
/*
* 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 */
extern int ext2_permission (struct inode *, int);
/* balloc.c */
-extern int ext2_new_block (struct super_block *, unsigned long);
-extern void ext2_free_block (struct super_block *, unsigned long);
+extern int ext2_new_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 void ext2_check_blocks_bitmap (struct super_block *);
extern void ext2_write_inode (struct inode *);
extern void ext2_put_inode (struct inode *);
extern int ext2_sync_inode (struct inode *);
+extern void ext2_discard_prealloc (struct inode *);
/* ioctl.c */
extern int ext2_ioctl (struct inode *, struct file *, unsigned int,
/* super.c */
extern void ext2_error (struct super_block *, const char *, const char *, ...)
__attribute__ ((format (printf, 3, 4)));
-extern volatile void ext2_panic (struct super_block *, const char *,
- const char *, ...)
- __attribute__ ((format (printf, 3, 4)));
+extern NORET_TYPE void ext2_panic (struct super_block *, const char *,
+ const char *, ...)
+ __attribute__ ((NORET_AND format (printf, 3, 4)));
extern void ext2_warning (struct super_block *, const char *, const char *, ...)
__attribute__ ((format (printf, 3, 4)));
extern void ext2_put_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 void ext2_statfs (struct super_block *, struct statfs *);
/*
* 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
*
unsigned long i_block_group;
unsigned long i_next_alloc_block;
unsigned long i_next_alloc_goal;
+ unsigned long i_prealloc_block;
+ unsigned long i_prealloc_count;
};
#endif /* _LINUX_EXT2_FS_I */
/*
* 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
*
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_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_groups_count; /* Number of groups in the fs */
struct buffer_head * s_sbh; /* Buffer containing the super block */
void (*put_super) (struct super_block *);
void (*write_super) (struct super_block *);
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 {
SS_UNCONNECTED, /* unconnected to any socket */
SS_CONNECTING, /* in process of connecting */
SS_CONNECTED, /* connected to socket */
- SS_DISCONNECTING, /* in process of disconnecting */
+ SS_DISCONNECTING /* in process of disconnecting */
} socket_state;
#define SO_ACCEPTCON (1<<16) /* performed a listen */
enum rpc_auth_flavor {
RPC_AUTH_NULL = 0,
RPC_AUTH_UNIX = 1,
- RPC_AUTH_SHORT = 2,
+ RPC_AUTH_SHORT = 2
};
enum rpc_msg_type {
RPC_CALL = 0,
- RPC_REPLY = 1,
+ RPC_REPLY = 1
};
enum rpc_reply_stat {
RPC_MSG_ACCEPTED = 0,
- RPC_MSG_DENIED = 1,
+ RPC_MSG_DENIED = 1
};
enum rpc_accept_stat {
RPC_PROG_UNAVAIL = 1,
RPC_PROG_MISMATCH = 2,
RPC_PROC_UNAVAIL = 3,
- RPC_GARBAGE_ARGS = 4,
+ RPC_GARBAGE_ARGS = 4
};
enum rpc_reject_stat {
RPC_MISMATCH = 0,
- RPC_AUTH_ERROR = 1,
+ RPC_AUTH_ERROR = 1
};
enum rpc_auth_stat {
RPC_AUTH_REJECTEDCRED = 2,
RPC_AUTH_BADVERF = 3,
RPC_AUTH_REJECTEDVERF = 4,
- RPC_AUTH_TOOWEAK = 5,
+ RPC_AUTH_TOOWEAK = 5
};
#endif /* __KERNEL__ */
NFSERR_NOTEMPTY = 66,
NFSERR_DQUOT = 69,
NFSERR_STALE = 70,
- NFSERR_WFLUSH = 99,
+ NFSERR_WFLUSH = 99
};
enum nfs_ftype {
NFLNK = 5,
NFSOCK = 6,
NFBAD = 7,
- NFFIFO = 8,
+ NFFIFO = 8
};
#define NFS_PROGRAM 100003
unsigned long paddr;
unsigned long router;
unsigned long net;
- unsigned long up:1,destroy:1;
+ unsigned int up:1,destroy:1;
};
#endif /* FIXME: */
} else {
if (!((dst ^ dev->pa_addr) & dev->pa_mask)) {
mask = dev->pa_mask;
- dst &= mask;
flags &= ~RTF_GATEWAY;
if (flags & RTF_DYNAMIC) {
/*printk("Dynamic route to my own net rejected\n");*/
}
} else
mask = guess_mask(dst);
+ dst &= mask;
}
if (gw == dev->pa_addr)
flags &= ~RTF_GATEWAY;
char *linux_banner =
"Linux version " UTS_RELEASE " (" LINUX_COMPILE_BY "@"
- LINUX_COMPILE_HOST "." LINUX_COMPILE_DOMAIN ") "
- UTS_VERSION ": " LINUX_COMPILE_TIME "\n";
+ LINUX_COMPILE_HOST ") " UTS_VERSION "\n";