Commit c6145b38 authored by Linus Torvalds's avatar Linus Torvalds

Import 0.99.14j

parent 27c43263
VERSION = 0.99
PATCHLEVEL = 14
ALPHA = i
ALPHA = j
all: Version zImage
......
......@@ -5,7 +5,7 @@
#
#
VERSION = 2.3
VERSION = 2.3b
TARGET_OS = linux
.c.s:
......
......@@ -178,7 +178,7 @@ static int dsp_set_stereo(int mode)
{
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)
*/
/*
......@@ -12,7 +14,6 @@
#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>
......@@ -25,10 +26,14 @@ int ext2_permission (struct inode * inode, int mask)
{
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>
......@@ -39,6 +40,8 @@
:"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;
......@@ -72,7 +75,9 @@ static inline int find_next_zero_bit (unsigned long * addr, int size,
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
......@@ -85,7 +90,9 @@ static inline int find_next_zero_bit (unsigned long * addr, int size,
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);
}
......@@ -109,32 +116,48 @@ static inline char * find_first_zero_byte (char * addr, int size)
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 long bitmap_nr)
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);
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;
}
......@@ -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[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];
......@@ -225,64 +246,70 @@ static inline int load_block_bitmap (struct super_block * sb,
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++;
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++;
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);
......@@ -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
* 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;
......@@ -329,34 +357,21 @@ int ext2_new_block (struct super_block * sb, unsigned long goal)
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
......@@ -366,8 +381,10 @@ int ext2_new_block (struct super_block * sb, unsigned long goal)
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)
......@@ -389,20 +406,22 @@ int ext2_new_block (struct super_block * sb, unsigned long goal)
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),
......@@ -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);
/* 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) {
......@@ -449,13 +452,12 @@ int ext2_new_block (struct super_block * sb, unsigned long goal)
}
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)) {
......@@ -465,25 +467,64 @@ int ext2_new_block (struct super_block * sb, unsigned long goal)
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"
......@@ -504,8 +545,8 @@ int ext2_new_block (struct super_block * sb, unsigned long goal)
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;
......@@ -518,8 +559,6 @@ unsigned long ext2_count_free_blocks (struct super_block * sb)
#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;
......@@ -528,38 +567,16 @@ unsigned long ext2_count_free_blocks (struct super_block * 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]) {
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],
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);
}
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);
......@@ -570,57 +587,57 @@ unsigned long ext2_count_free_blocks (struct super_block * sb)
#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]) {
gdp = get_group_desc (sb, i, NULL);
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",
"Descriptor not loaded for group %d",
"Block bitmap for group %d is marked free",
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;
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;
if (!block_in_use (gdp->bg_inode_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)
"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)
*
*/
......@@ -14,7 +16,6 @@
#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
*
......@@ -14,26 +16,32 @@
#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 */
......@@ -92,9 +100,9 @@ int ext2_check_dir_entry (char * function, struct inode * dir,
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;
......@@ -104,15 +112,35 @@ static int ext2_readdir (struct inode * inode, struct file * filp,
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,
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
*
......@@ -15,11 +17,11 @@
#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>
......@@ -32,8 +34,12 @@
#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
......@@ -48,7 +54,7 @@ static struct file_operations ext2_file_operations = {
ext2_ioctl, /* ioctl */
generic_mmap, /* mmap */
NULL, /* no special open is needed */
NULL, /* release */
ext2_release_file, /* release */
ext2_sync_file /* fsync */
};
......@@ -70,7 +76,10 @@ struct inode_operations ext2_file_inode_operations = {
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)
{
int read, left, chars;
......@@ -116,15 +125,17 @@ struct inode_operations ext2_file_inode_operations = {
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;
......@@ -140,8 +151,10 @@ struct inode_operations ext2_file_inode_operations = {
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;
......@@ -149,11 +162,16 @@ struct inode_operations ext2_file_inode_operations = {
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? */
......@@ -186,7 +204,9 @@ struct inode_operations ext2_file_inode_operations = {
} 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])
......@@ -217,6 +237,12 @@ static int ext2_file_write (struct inode * inode, struct file * filp,
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);
......@@ -269,3 +295,14 @@ static int ext2_file_write (struct inode * inode, struct file * filp,
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);
}
......@@ -4,6 +4,8 @@
* 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
*
......@@ -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) ||
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>
......@@ -59,28 +59,47 @@ static inline int find_first_zero_bit (unsigned long * addr, unsigned size)
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 = %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_inode_bitmap, sb->s_blocksize);
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;
}
......@@ -162,13 +181,13 @@ static int load_inode_bitmap (struct super_block * sb,
* 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);
......@@ -198,8 +217,6 @@ void ext2_free_inode (struct inode * inode)
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;
......@@ -241,28 +258,18 @@ void ext2_free_inode (struct inode * inode)
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) {
......@@ -310,22 +317,6 @@ static void inc_inode_version (struct inode * inode,
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
......@@ -340,10 +331,12 @@ struct inode * ext2_new_inode (const struct inode * dir, int mode)
{
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 ()))
......@@ -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 = 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;
......@@ -374,12 +367,12 @@ struct inode * ext2_new_inode (const struct inode * dir, int mode)
*/
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;
}
......@@ -388,18 +381,25 @@ struct inode * ext2_new_inode (const struct inode * dir, int mode)
}
}
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;
......@@ -407,12 +407,14 @@ struct inode * ext2_new_inode (const struct inode * dir, int mode)
}
}
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;
......@@ -428,9 +430,6 @@ struct inode * ext2_new_inode (const struct inode * dir, int mode)
}
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)) {
......@@ -447,9 +446,9 @@ struct inode * ext2_new_inode (const struct inode * dir, int mode)
} 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);
......@@ -458,7 +457,7 @@ struct inode * ext2_new_inode (const struct inode * dir, int mode)
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;
......@@ -468,7 +467,10 @@ struct inode * ext2_new_inode (const struct inode * dir, int mode)
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;
......@@ -499,8 +501,6 @@ unsigned long ext2_count_free_inodes (struct super_block * sb)
#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;
......@@ -509,36 +509,16 @@ unsigned long ext2_count_free_inodes (struct super_block * 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]) {
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);
}
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);
......@@ -553,8 +533,6 @@ void ext2_check_inodes_bitmap (struct super_block * sb)
{
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;
......@@ -563,42 +541,19 @@ void ext2_check_inodes_bitmap (struct super_block * 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_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)
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
*
......@@ -18,14 +20,22 @@
#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;
......@@ -48,6 +58,78 @@ static int block_bmap (struct buffer_head * bh, int nr)
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;
......@@ -147,12 +229,12 @@ static struct buffer_head * inode_getblk (struct inode * inode, int nr,
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;
}
......@@ -219,14 +301,14 @@ static struct buffer_head * block_getblk (struct inode * inode,
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;
}
......@@ -263,9 +345,11 @@ struct buffer_head * ext2_getblk (struct inode * inode, long block,
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,
......@@ -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_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
*
......@@ -16,7 +18,6 @@
#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>
......@@ -28,6 +29,14 @@
*/
/* #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.
*/
......@@ -38,7 +47,9 @@ static int ext2_match (int len, const char * const name,
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;
......@@ -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
* 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;
......@@ -83,34 +94,76 @@ static struct buffer_head * ext2_find_entry (struct inode * dir,
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;
}
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);
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;
}
failure:
for (i = 0; i < NAMEI_RA_SIZE; ++i)
brelse (bh_use[i]);
return NULL;
}
......@@ -187,8 +240,9 @@ static struct buffer_head * ext2_add_entry (struct inode * dir,
#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;
......@@ -231,7 +285,7 @@ static struct buffer_head * ext2_add_entry (struct inode * dir,
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)) {
*err = -ENOENT;
brelse (bh);
......@@ -295,13 +349,12 @@ static int ext2_delete_entry (struct ext2_dir_entry * dir,
pde = NULL;
de = (struct ext2_dir_entry *) bh->b_data;
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))
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;
}
......@@ -548,7 +601,7 @@ static int empty_dir (struct inode * inode)
}
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)) {
brelse (bh);
return 1;
......@@ -609,10 +662,13 @@ int ext2_rmdir (struct inode * dir, const char * name, int len)
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);
......@@ -969,14 +1025,18 @@ static int do_ext2_rename (struct inode * old_dir, const char * old_name,
&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
*
......@@ -18,7 +20,6 @@
#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>
......@@ -41,15 +42,22 @@ void ext2_error (struct super_block * sb, const char * function,
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,
NORET_TYPE void ext2_panic (struct super_block * sb, const char * function,
const char * fmt, ...)
{
char buf[1024];
......@@ -77,11 +85,7 @@ void ext2_warning (struct super_block * sb, const char * function,
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);
}
......@@ -181,15 +185,75 @@ static int parse_options (char * options, unsigned long * sb_block,
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 0;
......@@ -198,102 +262,191 @@ static int parse_options (char * options, unsigned long * sb_block,
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 /
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);
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);
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->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");
......@@ -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, "
"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;
......@@ -319,18 +472,18 @@ struct super_block * ext2_read_super (struct super_block * s, void * data,
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",
......@@ -338,98 +491,84 @@ struct super_block * ext2_read_super (struct super_block * s, void * data,
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 -
sb->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);
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;
}
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_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;
}
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,
......@@ -469,9 +608,16 @@ void ext2_write_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))
......@@ -480,9 +626,10 @@ int ext2_remount (struct super_block * sb, int * flags)
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;
......@@ -490,26 +637,14 @@ int ext2_remount (struct super_block * sb, int * flags)
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
*
......@@ -80,7 +82,7 @@ static int trunc_direct (struct inode * inode)
bh->b_dirt = 1;
}
brelse (bh);
ext2_free_block (inode->i_sb, tmp);
ext2_free_blocks (inode->i_sb, tmp, 1);
}
return retry;
}
......@@ -142,7 +144,7 @@ static int trunc_indirect (struct inode * inode, int offset, unsigned long * p)
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;
}
......@@ -158,7 +160,7 @@ static int trunc_indirect (struct inode * inode, int offset, unsigned long * p)
*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);
......@@ -218,7 +220,7 @@ static int trunc_dindirect (struct inode * inode, int offset,
*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);
......@@ -277,7 +279,7 @@ static int trunc_tindirect (struct inode * inode)
*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);
......@@ -294,6 +296,7 @@ void ext2_truncate (struct inode * inode)
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,
......@@ -312,13 +315,3 @@ void ext2_truncate (struct inode * inode)
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");
}
......@@ -36,7 +36,7 @@ extern int root_mountflags;
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;
......@@ -210,7 +210,7 @@ static int do_umount(dev_t dev)
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;
}
......@@ -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.
*/
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;
......@@ -353,7 +353,7 @@ static int do_remount_sb(struct super_block *sb, int flags)
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;
}
......@@ -362,7 +362,7 @@ static int do_remount_sb(struct super_block *sb, int flags)
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;
......@@ -374,23 +374,54 @@ static int do_remount(const char *dir,int flags)
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)
......@@ -400,27 +431,29 @@ asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type,
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 (type) {
for (i = 0 ; i < 100 ; i++) {
if (TASK_SIZE <= (unsigned long) type)
return -EFAULT;
if (!(tmp[i] = get_fs_byte(type++)))
break;
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;
}
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) {
......@@ -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) {
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) {
retval = copy_mount_options(data, &page);
if (retval < 0) {
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);
return retval;
}
}
retval = do_mount(dev,dir_name,t,flags,(void *) page);
......
......@@ -7,7 +7,7 @@
* 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
*/
......@@ -24,73 +24,41 @@
#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
......@@ -117,4 +85,44 @@ __asm__ __volatile__ ("inb %1,%b0"
__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
......@@ -35,7 +35,7 @@ extern void enable_irq(unsigned int);
"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
*
......@@ -38,20 +40,20 @@
#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
......@@ -242,13 +244,33 @@ struct ext2_inode {
/*
* 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
*/
......@@ -270,7 +292,9 @@ struct ext2_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 */
};
/*
......@@ -300,12 +324,28 @@ struct ext2_dir_entry {
* 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 *);
......@@ -351,6 +391,7 @@ extern void ext2_read_inode (struct inode *);
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,
......@@ -374,14 +415,14 @@ extern int ext2_rename (struct inode *, const char *, 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 *,
extern NORET_TYPE void ext2_panic (struct super_block *, 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 *, ...)
__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
*
......@@ -30,6 +32,8 @@ struct ext2_inode_info {
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
*
......@@ -26,6 +28,7 @@ struct ext2_sb_info {
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 */
......
......@@ -300,7 +300,7 @@ struct super_operations {
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 {
......
......@@ -49,7 +49,7 @@ typedef enum {
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 */
......
......@@ -25,17 +25,17 @@
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 {
......@@ -43,12 +43,12 @@ 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 {
......@@ -56,7 +56,7 @@ 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__ */
......@@ -80,7 +80,7 @@ enum nfs_stat {
NFSERR_NOTEMPTY = 66,
NFSERR_DQUOT = 69,
NFSERR_STALE = 70,
NFSERR_WFLUSH = 99,
NFSERR_WFLUSH = 99
};
enum nfs_ftype {
......@@ -92,7 +92,7 @@ enum nfs_ftype {
NFLNK = 5,
NFSOCK = 6,
NFBAD = 7,
NFFIFO = 8,
NFFIFO = 8
};
#define NFS_PROGRAM 100003
......
......@@ -28,7 +28,7 @@ struct ip_config {
unsigned long paddr;
unsigned long router;
unsigned long net;
unsigned long up:1,destroy:1;
unsigned int up:1,destroy:1;
};
#endif /* FIXME: */
......
......@@ -170,7 +170,6 @@ rt_add(short flags, unsigned long dst, unsigned long gw, struct device *dev)
} 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");*/
......@@ -178,6 +177,7 @@ rt_add(short flags, unsigned long dst, unsigned long gw, struct device *dev)
}
} else
mask = guess_mask(dst);
dst &= mask;
}
if (gw == dev->pa_addr)
flags &= ~RTF_GATEWAY;
......
......@@ -18,5 +18,4 @@ struct new_utsname system_utsname = {
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";
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