From c6145b384a44636d62352bc5e48acd6e03b7a76f Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 23 Nov 2007 15:09:17 -0500 Subject: [PATCH] Import 0.99.14j --- Makefile | 2 +- drivers/sound/Makefile | 2 +- drivers/sound/sb16_dsp.c | 2 +- fs/ext2/acl.c | 13 +- fs/ext2/balloc.c | 409 ++++++++++++++++---------------- fs/ext2/bitmap.c | 4 +- fs/ext2/dcache.c | 5 +- fs/ext2/dir.c | 48 +++- fs/ext2/file.c | 77 ++++-- fs/ext2/fsync.c | 6 +- fs/ext2/ialloc.c | 229 ++++++++---------- fs/ext2/inode.c | 105 ++++++++- fs/ext2/ioctl.c | 4 +- fs/ext2/namei.c | 152 ++++++++---- fs/ext2/super.c | 463 ++++++++++++++++++++++++------------- fs/ext2/symlink.c | 4 +- fs/ext2/truncate.c | 25 +- fs/super.c | 111 +++++---- include/asm/io.h | 144 ++++++------ include/asm/irq.h | 2 +- include/linux/ext2_fs.h | 73 ++++-- include/linux/ext2_fs_i.h | 6 +- include/linux/ext2_fs_sb.h | 5 +- include/linux/fs.h | 2 +- include/linux/net.h | 2 +- include/linux/nfs.h | 16 +- include/linux/sockios.h | 2 +- net/inet/route.c | 2 +- tools/version.c | 3 +- 29 files changed, 1159 insertions(+), 759 deletions(-) diff --git a/Makefile b/Makefile index dbbe935b028d..5761b0840551 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 0.99 PATCHLEVEL = 14 -ALPHA = i +ALPHA = j all: Version zImage diff --git a/drivers/sound/Makefile b/drivers/sound/Makefile index 6b58c2842277..1f3760aae095 100644 --- a/drivers/sound/Makefile +++ b/drivers/sound/Makefile @@ -5,7 +5,7 @@ # # -VERSION = 2.3 +VERSION = 2.3b TARGET_OS = linux .c.s: diff --git a/drivers/sound/sb16_dsp.c b/drivers/sound/sb16_dsp.c index 4c799c061ec4..e8e25cc71715 100644 --- a/drivers/sound/sb16_dsp.c +++ b/drivers/sound/sb16_dsp.c @@ -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; } diff --git a/fs/ext2/acl.c b/fs/ext2/acl.c index 2103f8130d28..421fc11fc88d 100644 --- a/fs/ext2/acl.c +++ b/fs/ext2/acl.c @@ -1,7 +1,9 @@ /* * 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 #include #include -#include #include #include @@ -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)) diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c index d5cf2d039485..96d0ab1953da 100644 --- a/fs/ext2/balloc.c +++ b/fs/ext2/balloc.c @@ -1,29 +1,30 @@ /* * 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 #include -#include #include #include #include @@ -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, - unsigned int block_group, - unsigned long bitmap_nr) +static struct ext2_group_desc * get_group_desc (struct super_block * sb, + unsigned int block_group, + struct buffer_head ** bh) { unsigned long group_desc; unsigned long desc; struct ext2_group_desc * gdp; - struct buffer_head * bh; - + + if (block_group >= sb->u.ext2_sb.s_groups_count) + ext2_panic (sb, "get_group_desc", + "block_group >= groups_count\n" + "block_group = %d, groups_count = %lu", + block_group, sb->u.ext2_sb.s_groups_count); + group_desc = block_group / EXT2_DESC_PER_BLOCK(sb); desc = block_group % EXT2_DESC_PER_BLOCK(sb); if (!sb->u.ext2_sb.s_group_desc[group_desc]) - ext2_panic (sb, "read_block_bitmap", + ext2_panic (sb, "get_group_desc", "Group descriptor not loaded\n" "block_group = %d, group_desc = %lu, desc = %lu", block_group, group_desc, desc); gdp = (struct ext2_group_desc *) - sb->u.ext2_sb.s_group_desc[group_desc]->b_data; - bh = bread (sb->s_dev, gdp[desc].bg_block_bitmap, sb->s_blocksize); + sb->u.ext2_sb.s_group_desc[group_desc]->b_data; + if (bh) + *bh = sb->u.ext2_sb.s_group_desc[group_desc]; + return gdp + desc; +} + +static void read_block_bitmap (struct super_block * sb, + unsigned int block_group, + unsigned long bitmap_nr) +{ + struct ext2_group_desc * gdp; + struct buffer_head * bh; + + gdp = get_group_desc (sb, block_group, NULL); + bh = bread (sb->s_dev, gdp->bg_block_bitmap, sb->s_blocksize); if (!bh) ext2_panic (sb, "read_block_bitmap", "Cannot read block bitmap\n" - "block_group = %d, group_desc = %lu," - "desc = %lu, block_bitmap = %lu", - block_group, group_desc, desc, - gdp[desc].bg_block_bitmap); + "block_group = %d, block_bitmap = %lu", + block_group, gdp->bg_block_bitmap); sb->u.ext2_sb.s_block_bitmap_number[bitmap_nr] = block_group; sb->u.ext2_sb.s_block_bitmap[bitmap_nr] = bh; } @@ -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++; - bh2->b_dirt = 1; - es->s_free_blocks_count++; - sb->u.ext2_sb.s_sbh->b_dirt = 1; + gdp = get_group_desc (sb, block_group, &bh2); + + if (test_opt (sb, CHECK_STRICT) && + (in_range (gdp->bg_block_bitmap, block, count) || + in_range (gdp->bg_inode_bitmap, block, count) || + in_range (block, gdp->bg_inode_table, + sb->u.ext2_sb.s_itb_per_group) || + in_range (block + count - 1, gdp->bg_inode_table, + sb->u.ext2_sb.s_itb_per_group))) + ext2_panic (sb, "ext2_free_blocks", + "Freeing blocks in system zones\n" + "Block = %lu, count = %lu", + block, count); + + for (i = 0; i < count; i++) { + if (!clear_bit (bit + i, bh->b_data)) + ext2_warning (sb, "ext2_free_blocks", + "bit already cleared for block %lu", + block); } + + gdp->bg_free_blocks_count += count; + bh2->b_dirt = 1; + es->s_free_blocks_count += count; + sb->u.ext2_sb.s_sbh->b_dirt = 1; + bh->b_dirt = 1; if (sb->s_flags & MS_SYNC) { ll_rw_block (WRITE, 1, &bh); @@ -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 @@ repeat: 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 @@ repeat: 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 @@ repeat: 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 @@ repeat: } 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)) { @@ -464,26 +466,65 @@ repeat: unlock_super (sb); return 0; } - + +search_back: + /* + * We have succeeded in finding a free byte in the block + * bitmap. Now search backwards up to 7 bits to find the + * start of this group of free blocks. + */ + for (k = 0; k < 7 && j > 0 && !test_bit (j - 1, bh->b_data); k++, j--); + got_block: - ext2_debug ("using block group %d(%lu,%lu,%d)\n", - i, group_desc, desc, gdp[desc].bg_free_blocks_count); + ext2_debug ("using block group %d(%d)\n", i, gdp->bg_free_blocks_count); + + tmp = j + i * EXT2_BLOCKS_PER_GROUP(sb) + es->s_first_data_block; + + if (test_opt (sb, CHECK_STRICT) && + (tmp == gdp->bg_block_bitmap || + tmp == gdp->bg_inode_bitmap || + in_range (tmp, gdp->bg_inode_table, sb->u.ext2_sb.s_itb_per_group))) + ext2_panic (sb, "ext2_new_block", + "Allocating block in system zone\nblock = %u", + tmp); if (set_bit (j, bh->b_data)) { ext2_warning (sb, "ext2_new_block", "bit already set for block %d", j); goto repeat; } + + ext2_debug ("found bit %d\n", j); + + /* + * Do block preallocation now if required. + */ +#ifdef EXT2_PREALLOCATE + if (prealloc_block) { + *prealloc_count = 0; + *prealloc_block = tmp + 1; + for (k = 1; + k < 8 && (j + k) < EXT2_BLOCKS_PER_GROUP(sb); k++) { + if (set_bit (j + k, bh->b_data)) + break; + (*prealloc_count)++; + } + gdp->bg_free_blocks_count -= *prealloc_count; + es->s_free_blocks_count -= *prealloc_count; + ext2_debug ("Preallocated a further %lu bits.\n", + *prealloc_count); + } +#endif + + j = tmp; + bh->b_dirt = 1; if (sb->s_flags & MS_SYNC) { ll_rw_block (WRITE, 1, &bh); wait_on_buffer (bh); } - ext2_debug ("found bit %d\n", j); - - j += i * EXT2_BLOCKS_PER_GROUP(sb) + es->s_first_data_block; if (j >= es->s_blocks_count) { ext2_error (sb, "ext2_new_block", "block >= blocks count\n" @@ -504,8 +545,8 @@ got_block: 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], - sb->s_blocksize); - else { - x = 0; - printk ("Cannot load bitmap for group %d\n", i); - } + x = ext2_count_free (sb->u.ext2_sb.s_block_bitmap[bitmap_nr], + sb->s_blocksize); printk ("group %d: stored = %d, counted = %lu\n", - i, gdp[desc].bg_free_blocks_count, x); + i, gdp->bg_free_blocks_count, x); bitmap_count += x; - desc++; - if (desc == EXT2_DESC_PER_BLOCK(sb)) { - group_desc++; - desc = 0; - gdp = NULL; - } } printk("ext2_count_free_blocks: stored = %lu, computed = %lu, %lu\n", es->s_free_blocks_count, desc_count, bitmap_count); @@ -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]) { - ext2_error (sb, "ext2_check_blocks_bitmap", - "Descriptor not loaded for group %d", - i); - break; - } - gdp = (struct ext2_group_desc *) - sb->u.ext2_sb.s_group_desc[group_desc]->b_data; - } - desc_count += gdp[desc].bg_free_blocks_count; + gdp = get_group_desc (sb, i, NULL); + desc_count += gdp->bg_free_blocks_count; bitmap_nr = load_block_bitmap (sb, i); - if (sb->u.ext2_sb.s_block_bitmap[bitmap_nr]) - x = ext2_count_free - (sb->u.ext2_sb.s_block_bitmap[bitmap_nr], - sb->s_blocksize); - else { - x = 0; + bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr]; + + if (!block_in_use (gdp->bg_block_bitmap, sb, bh->b_data)) ext2_error (sb, "ext2_check_blocks_bitmap", - "Cannot load bitmap for group %d\n", i); - } - if (gdp[desc].bg_free_blocks_count != x) + "Block bitmap for group %d is marked free", + i); + + if (!block_in_use (gdp->bg_inode_bitmap, sb, bh->b_data)) + ext2_error (sb, "ext2_check_blocks_bitmap", + "Inode bitmap for group %d is marked free", + i); + + for (j = 0; j < sb->u.ext2_sb.s_itb_per_group; j++) + if (!block_in_use (gdp->bg_inode_table + j, sb, bh->b_data)) + ext2_error (sb, "ext2_check_blocks_bitmap", + "Block #%d of the inode table in group %d " + "is marked free", j, i); + + x = ext2_count_free (bh, sb->s_blocksize); + if (gdp->bg_free_blocks_count != x) ext2_error (sb, "ext2_check_blocks_bitmap", "Wrong free blocks count for group %d, " "stored = %d, counted = %lu", i, - gdp[desc].bg_free_blocks_count, x); + gdp->bg_free_blocks_count, x); bitmap_count += x; - desc++; - if (desc == EXT2_DESC_PER_BLOCK(sb)) { - group_desc++; - desc = 0; - gdp = NULL; - } } if (es->s_free_blocks_count != bitmap_count) ext2_error (sb, "ext2_check_blocks_bitmap", diff --git a/fs/ext2/bitmap.c b/fs/ext2/bitmap.c index 70278ae05613..1084da16d2e0 100644 --- a/fs/ext2/bitmap.c +++ b/fs/ext2/bitmap.c @@ -1,7 +1,9 @@ /* * 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 diff --git a/fs/ext2/dcache.c b/fs/ext2/dcache.c index 8c3e69f756c6..324ddaee43b0 100644 --- a/fs/ext2/dcache.c +++ b/fs/ext2/dcache.c @@ -1,7 +1,9 @@ /* * 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 #include -#include #include #ifndef DONT_USE_DCACHE diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c index 24725fbb3baa..9cfff70a3dc1 100644 --- a/fs/ext2/dir.c +++ b/fs/ext2/dir.c @@ -1,7 +1,9 @@ /* * 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 +#include #include #include #include #include #include -#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,16 +112,36 @@ 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, - bh, offset)) { + if (!ext2_check_dir_entry ("ext2_readdir", inode, de, + bh, offset)) { brelse (bh); return 0; } diff --git a/fs/ext2/file.c b/fs/ext2/file.c index 4dd553dfcf29..e0e9e98cdb9f 100644 --- a/fs/ext2/file.c +++ b/fs/ext2/file.c @@ -1,7 +1,9 @@ /* * 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 #include +#include #include #include #include #include -#include #include #include #include @@ -32,8 +34,12 @@ #include #include -/* 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,8 +76,11 @@ struct inode_operations ext2_file_inode_operations = { ext2_permission /* permission */ }; -/* static */ int ext2_file_read (struct inode * inode, struct file * filp, - char * buf, int count) +#ifndef CONFIG_EXT2_FS_DIR_READ +static +#endif +int ext2_file_read (struct inode * inode, struct file * filp, + char * buf, int count) { int read, left, chars; int block, blocks, offset; @@ -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); +} diff --git a/fs/ext2/fsync.c b/fs/ext2/fsync.c index 9a11cccf6d26..2f79c474988e 100644 --- a/fs/ext2/fsync.c +++ b/fs/ext2/fsync.c @@ -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++) diff --git a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c index 81053de8946a..d44856b693ff 100644 --- a/fs/ext2/ialloc.c +++ b/fs/ext2/ialloc.c @@ -1,31 +1,31 @@ - /* * 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 #include -#include #include #include #include @@ -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, group_desc, desc); - gdp = (struct ext2_group_desc *) sb->u.ext2_sb.s_group_desc[group_desc]->b_data; - bh = bread (sb->s_dev, gdp[desc].bg_inode_bitmap, sb->s_blocksize); + "block_group = %d, group_desc = %lu, desc = %lu", + block_group, group_desc, desc); + gdp = (struct ext2_group_desc *) + sb->u.ext2_sb.s_group_desc[group_desc]->b_data; + if (bh) + *bh = sb->u.ext2_sb.s_group_desc[group_desc]; + return gdp + desc; +} + +static void read_inode_bitmap (struct super_block * sb, + unsigned long block_group, + unsigned int bitmap_nr) +{ + struct ext2_group_desc * gdp; + struct buffer_head * bh; + + gdp = get_group_desc (sb, block_group, NULL); + bh = bread (sb->s_dev, gdp->bg_inode_bitmap, sb->s_blocksize); if (!bh) ext2_panic (sb, "read_inode_bitmap", "Cannot read inode bitmap\n" - "block_group = %lu, group_desc = %lu, desc = %lu, inode_bitmap = %lu", - block_group, group_desc, desc, gdp[desc].bg_inode_bitmap); + "block_group = %lu, inode_bitmap = %lu", + block_group, gdp->bg_inode_bitmap); sb->u.ext2_sb.s_inode_bitmap_number[bitmap_nr] = block_group; sb->u.ext2_sb.s_inode_bitmap[bitmap_nr] = bh; } @@ -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 @@ repeat: /* 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 @@ repeat: */ 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 @@ repeat: } } 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 @@ repeat: } } 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; @@ -420,7 +422,7 @@ repeat: } } } - + if (!gdp) { unlock_super (sb); iput(inode); @@ -428,9 +430,6 @@ repeat: } 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 @@ repeat: } 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 @@ repeat: 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 @@ repeat: 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); - } + x = ext2_count_free (sb->u.ext2_sb.s_inode_bitmap[bitmap_nr], + EXT2_INODES_PER_GROUP(sb) / 8); printk ("group %d: stored = %d, counted = %lu\n", - i, gdp[desc].bg_free_inodes_count, x); + i, gdp->bg_free_inodes_count, x); bitmap_count += x; - desc++; - if (desc == EXT2_DESC_PER_BLOCK(sb)) { - group_desc++; - desc = 0; - gdp = NULL; - } } printk("ext2_count_free_inodes: stored = %lu, computed = %lu, %lu\n", es->s_free_inodes_count, desc_count, bitmap_count); @@ -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) + x = ext2_count_free (sb->u.ext2_sb.s_inode_bitmap[bitmap_nr], + EXT2_INODES_PER_GROUP(sb) / 8); + if (gdp->bg_free_inodes_count != x) ext2_error (sb, "ext2_check_inodes_bitmap", "Wrong free inodes count in group %d, " "stored = %d, counted = %lu", i, - gdp[desc].bg_free_inodes_count, x); + gdp->bg_free_inodes_count, x); bitmap_count += x; - desc++; - if (desc == EXT2_DESC_PER_BLOCK(sb)) { - group_desc++; - desc = 0; - gdp = NULL; - } } if (es->s_free_inodes_count != bitmap_count) ext2_error (sb, "ext2_check_inodes_bitmap", diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index 92c8bdfc98fa..bbc1e5261126 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c @@ -1,7 +1,9 @@ /* * 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 #include #include -#include #include #include #include #include +#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 @@ repeat: 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 @@ repeat: if (!goal) goal = bh->b_blocknr + 1; } - tmp = ext2_new_block (inode->i_sb, goal); + tmp = ext2_alloc_block (inode, goal); if (!tmp) { brelse (bh); return NULL; } result = getblk (bh->b_dev, tmp, blocksize); if (*p) { - ext2_free_block (inode->i_sb, tmp); + ext2_free_blocks (inode->i_sb, tmp, 1); brelse (result); goto repeat; } @@ -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++) diff --git a/fs/ext2/ioctl.c b/fs/ext2/ioctl.c index d01f9ef4f06f..8c103ae4cbe2 100644 --- a/fs/ext2/ioctl.c +++ b/fs/ext2/ioctl.c @@ -1,7 +1,9 @@ /* * 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 diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c index ff0496826470..d5a47b2a920f 100644 --- a/fs/ext2/namei.c +++ b/fs/ext2/namei.c @@ -1,7 +1,9 @@ /* * 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 #include #include -#include #include #include #include @@ -27,7 +28,15 @@ * truncated. Else they will be disallowed. */ /* #define NO_TRUNCATE */ - + +/* + * define how far ahead to read directories while searching them. + */ +#define NAMEI_RA_CHUNKS 2 +#define NAMEI_RA_BLOCKS 4 +#define NAMEI_RA_SIZE (NAMEI_RA_CHUNKS * NAMEI_RA_BLOCKS) +#define NAMEI_RA_INDEX(c,b) (((c) * NAMEI_RA_BLOCKS) + (b)) + /* * NOTE! unlike strncmp, ext2_match returns 1 for success, 0 for failure. */ @@ -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; } - if (de->inode != 0 && ext2_match (namelen, name, de)) { - *res_dir = de; - return bh; + + de = (struct ext2_dir_entry *) bh->b_data; + dlimit = bh->b_data + sb->s_blocksize; + while ((char *) de < dlimit) { + if (!ext2_check_dir_entry ("ext2_find_entry", dir, + de, bh, offset)) + goto failure; + if (de->inode != 0 && ext2_match (namelen, name, de)) { + for (i = 0; i < NAMEI_RA_SIZE; ++i) { + if (bh_use[i] != bh) + brelse (bh_use[i]); + } + *res_dir = de; + return bh; + } + offset += de->rec_len; + de = (struct ext2_dir_entry *) + ((char *) de + de->rec_len); } - offset += de->rec_len; - de = (struct ext2_dir_entry *) ((char *) de + de->rec_len); + + brelse (bh); + if (((block + NAMEI_RA_SIZE) << EXT2_BLOCK_SIZE_BITS (sb)) >= + dir->i_size) + bh = NULL; + else + bh = ext2_getblk (dir, block + NAMEI_RA_SIZE, 0, &err); + bh_use[block++ % NAMEI_RA_SIZE] = bh; + if (bh && !bh->b_uptodate) + bh_read[toread++] = bh; } - brelse (bh); + +failure: + for (i = 0; i < NAMEI_RA_SIZE; ++i) + brelse (bh_use[i]); return NULL; } @@ -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,8 +285,8 @@ 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, - offset)) { + if (!ext2_check_dir_entry ("ext2_add_entry", dir, de, bh, + offset)) { *err = -ENOENT; brelse (bh); return NULL; @@ -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, - de, bh, i)) + if (!ext2_check_dir_entry ("ext2_delete_entry", NULL, + de, bh, i)) return -EIO; if (de == dir) { if (pde) pde->rec_len += dir->rec_len; - /* XXX - must zero the inode number in every case !! */ dir->inode = 0; return 0; } @@ -548,8 +601,8 @@ 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, - offset)) { + if (!ext2_check_dir_entry ("empty_dir", inode, de, bh, + offset)) { brelse (bh); return 1; } @@ -609,10 +662,13 @@ repeat: 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 @@ start_up: &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, diff --git a/fs/ext2/super.c b/fs/ext2/super.c index 63bce7edafb8..766179f20fbd 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c @@ -1,7 +1,9 @@ /* * 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 #include #include -#include #include #include #include @@ -41,16 +42,23 @@ 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, - const char * fmt, ...) +NORET_TYPE void ext2_panic (struct super_block * sb, const char * function, + const char * fmt, ...) { char buf[1024]; va_list args; @@ -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,14 +185,74 @@ 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); @@ -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 / - sizeof (struct ext2_inode); - s->u.ext2_sb.s_desc_per_block = s->s_blocksize / - sizeof (struct ext2_group_desc); - s->u.ext2_sb.s_sbh = bh; - s->u.ext2_sb.s_es = es; - s->u.ext2_sb.s_mount_state = es->s_state; - s->u.ext2_sb.s_rename_lock = 0; - s->u.ext2_sb.s_rename_wait = NULL; + sb->s_magic = 0; + sb->u.ext2_sb.s_blocks_per_group = es->s_blocks_per_group; + sb->u.ext2_sb.s_frags_per_group = es->s_frags_per_group; + sb->u.ext2_sb.s_inodes_per_group = es->s_inodes_per_group; + sb->u.ext2_sb.s_inodes_per_block = sb->s_blocksize / + sizeof (struct ext2_inode); + sb->u.ext2_sb.s_itb_per_group = sb->u.ext2_sb.s_inodes_per_group / + sb->u.ext2_sb.s_inodes_per_block; + sb->u.ext2_sb.s_desc_per_block = sb->s_blocksize / + sizeof (struct ext2_group_desc); + sb->u.ext2_sb.s_sbh = bh; + sb->u.ext2_sb.s_es = es; + sb->u.ext2_sb.s_mount_state = es->s_state; + sb->u.ext2_sb.s_rename_lock = 0; + sb->u.ext2_sb.s_rename_wait = NULL; #ifdef EXT2FS_PRE_02B_COMPAT - if (s->s_magic == EXT2_PRE_02B_MAGIC) { + if (sb->s_magic == EXT2_PRE_02B_MAGIC) { if (es->s_blocks_count > 262144) { - /* fs > 256 MB can't be converted */ - s->s_dev = 0; - unlock_super (s); + /* + * fs > 256 MB can't be converted + */ + sb->s_dev = 0; + unlock_super (sb); brelse (bh); printk ("EXT2-fs: trying to mount a pre-0.2b file" "system which cannot be converted\n"); @@ -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 - - es->s_first_data_block + - EXT2_BLOCKS_PER_GROUP(s) - 1) / - EXT2_BLOCKS_PER_GROUP(s); + sb->u.ext2_sb.s_groups_count = (es->s_blocks_count - + es->s_first_data_block + + EXT2_BLOCKS_PER_GROUP(sb) - 1) / + EXT2_BLOCKS_PER_GROUP(sb); for (i = 0; i < EXT2_MAX_GROUP_DESC; i++) - s->u.ext2_sb.s_group_desc[i] = NULL; - bh_count = (s->u.ext2_sb.s_groups_count + EXT2_DESC_PER_BLOCK(s) - 1) / - EXT2_DESC_PER_BLOCK(s); + sb->u.ext2_sb.s_group_desc[i] = NULL; + bh_count = (sb->u.ext2_sb.s_groups_count + EXT2_DESC_PER_BLOCK(sb) - 1) / + EXT2_DESC_PER_BLOCK(sb); if (bh_count > EXT2_MAX_GROUP_DESC) { - s->s_dev = 0; - unlock_super (s); + sb->s_dev = 0; + unlock_super (sb); brelse (bh); printk ("EXT2-fs: file system is too big\n"); return NULL; } for (i = 0; i < bh_count; i++) { - s->u.ext2_sb.s_group_desc[i] = bread (dev, logic_sb_block + i + 1, - s->s_blocksize); - if (!s->u.ext2_sb.s_group_desc[i]) { - s->s_dev = 0; - unlock_super (s); + sb->u.ext2_sb.s_group_desc[i] = bread (dev, logic_sb_block + i + 1, + sb->s_blocksize); + if (!sb->u.ext2_sb.s_group_desc[i]) { + sb->s_dev = 0; + unlock_super (sb); for (j = 0; j < i; j++) - brelse (s->u.ext2_sb.s_group_desc[i]); + brelse (sb->u.ext2_sb.s_group_desc[i]); brelse (bh); printk ("EXT2-fs: unable to read group descriptors\n"); return NULL; } } + if (!ext2_check_descriptors (sb)) { + sb->s_dev = 0; + unlock_super (sb); + for (j = 0; j < i; j++) + brelse (sb->u.ext2_sb.s_group_desc[i]); + brelse (bh); + printk ("EXT2-fs: group descriptors corrupted !\n"); + return NULL; + } for (i = 0; i < EXT2_MAX_GROUP_LOADED; i++) { - s->u.ext2_sb.s_inode_bitmap_number[i] = 0; - s->u.ext2_sb.s_inode_bitmap[i] = NULL; - s->u.ext2_sb.s_block_bitmap_number[i] = 0; - s->u.ext2_sb.s_block_bitmap[i] = NULL; + sb->u.ext2_sb.s_inode_bitmap_number[i] = 0; + sb->u.ext2_sb.s_inode_bitmap[i] = NULL; + sb->u.ext2_sb.s_block_bitmap_number[i] = 0; + sb->u.ext2_sb.s_block_bitmap[i] = NULL; } - s->u.ext2_sb.s_loaded_inode_bitmaps = 0; - s->u.ext2_sb.s_loaded_block_bitmaps = 0; - unlock_super (s); - /* set up enough so that it can read an inode */ - s->s_dev = dev; - s->s_op = &ext2_sops; - if (!(s->s_mounted = iget (s, EXT2_ROOT_INO))) { - s->s_dev = 0; + sb->u.ext2_sb.s_loaded_inode_bitmaps = 0; + sb->u.ext2_sb.s_loaded_block_bitmaps = 0; + unlock_super (sb); + /* + * set up enough so that it can read an inode + */ + sb->s_dev = dev; + sb->s_op = &ext2_sops; + if (!(sb->s_mounted = iget (sb, EXT2_ROOT_INO))) { + sb->s_dev = 0; for (i = 0; i < EXT2_MAX_GROUP_DESC; i++) - if (s->u.ext2_sb.s_group_desc[i]) - brelse (s->u.ext2_sb.s_group_desc[i]); + if (sb->u.ext2_sb.s_group_desc[i]) + brelse (sb->u.ext2_sb.s_group_desc[i]); brelse (bh); printk ("EXT2-fs: get root inode failed\n"); return NULL; } - if (!(s->s_flags & MS_RDONLY)) { - es->s_state &= ~EXT2_VALID_FS; - if (!es->s_max_mnt_count) - es->s_max_mnt_count = EXT2_DFL_MAX_MNT_COUNT; - es->s_mnt_count++; - es->s_mtime = CURRENT_TIME; - bh->b_dirt = 1; - s->s_dirt = 1; - } #ifdef EXT2FS_PRE_02B_COMPAT if (fs_converted) { for (i = 0; i < bh_count; i++) - s->u.ext2_sb.s_group_desc[i]->b_dirt = 1; - s->s_dirt = 1; + sb->u.ext2_sb.s_group_desc[i]->b_dirt = 1; + sb->s_dirt = 1; } #endif - if (!(s->u.ext2_sb.s_mount_state & EXT2_VALID_FS)) - printk ("EXT2-fs warning: mounting unchecked file system, " - "running e2fsck is recommended\n"); - else if (s->u.ext2_sb.s_mount_state & EXT2_ERROR_FS) - printk ("EXT2-fs warning: mounting file system with errors, " - "running e2fsck is recommended\n"); - else if (es->s_mnt_count >= es->s_max_mnt_count) - printk ("EXT2-fs warning: maximal mount count reached, " - "running e2fsck is recommended\n"); - if (s->u.ext2_sb.s_mount_opt & EXT2_MOUNT_CHECK) { - printk ("[EXT II FS %s, %s, bs=%lu, fs=%lu, gc=%lu, bpg=%lu, ipg=%lu]\n", - EXT2FS_VERSION, EXT2FS_DATE, s->s_blocksize, - s->u.ext2_sb.s_frag_size, s->u.ext2_sb.s_groups_count, - EXT2_BLOCKS_PER_GROUP(s), EXT2_INODES_PER_GROUP(s)); - ext2_check_blocks_bitmap (s); - ext2_check_inodes_bitmap (s); - } - return s; + ext2_setup_super (sb, es); + return sb; } static void ext2_commit_super (struct super_block * sb, @@ -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; } diff --git a/fs/ext2/symlink.c b/fs/ext2/symlink.c index d6cff0ad5863..a98ed66bbffb 100644 --- a/fs/ext2/symlink.c +++ b/fs/ext2/symlink.c @@ -1,7 +1,9 @@ /* * 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 * diff --git a/fs/ext2/truncate.c b/fs/ext2/truncate.c index 9b67d35f5bed..aa366c71fe0f 100644 --- a/fs/ext2/truncate.c +++ b/fs/ext2/truncate.c @@ -1,7 +1,9 @@ /* * 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 @@ repeat: 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 @@ repeat: 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 @@ repeat: *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 @@ repeat: *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 @@ repeat: *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"); -} diff --git a/fs/super.c b/fs/super.c index 089f6f386d3d..dbbfb67a8559 100644 --- a/fs/super.c +++ b/fs/super.c @@ -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 ((new_flags & + (MS_MGC_MSK | MS_REMOUNT)) == (MS_MGC_VAL | MS_REMOUNT)) { + retval = copy_mount_options (data, &page); + if (retval < 0) + return retval; + retval = do_remount(dir_name, + new_flags & ~MS_MGC_MSK & ~MS_REMOUNT, + (char *) page); + free_page(page); + return retval; } - if (type) { - for (i = 0 ; i < 100 ; i++) { - if (TASK_SIZE <= (unsigned long) type) - return -EFAULT; - if (!(tmp[i] = get_fs_byte(type++))) - break; - } - t = tmp; - } else - t = NULL; - if (!(fstype = get_fs_type(t))) + retval = copy_mount_options (type, &page); + if (retval < 0) + return retval; + fstype = get_fs_type((char *) page); + free_page(page); + if (!fstype) return -ENODEV; t = fstype->name; if (fstype->requires_dev) { @@ -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) { - iput(inode); - return -EFAULT; - } - if ((unsigned long) data < vma->vm_end) - break; - vma = vma->vm_next; - } - i = vma->vm_end - (unsigned long) data; - if (PAGE_SIZE <= (unsigned long) i) - i = PAGE_SIZE-1; - if (!(page = __get_free_page(GFP_KERNEL))) { - iput(inode); - return -ENOMEM; - } - memcpy_fromfs((void *) page,data,i); + retval = copy_mount_options(data, &page); + if (retval < 0) { + iput(inode); + return retval; } } retval = do_mount(dev,dir_name,t,flags,(void *) page); diff --git a/include/asm/io.h b/include/asm/io.h index c0cbcd16137c..b51095970a8f 100644 --- a/include/asm/io.h +++ b/include/asm/io.h @@ -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 diff --git a/include/asm/irq.h b/include/asm/irq.h index 191a6685ea68..b9d878105b82 100644 --- a/include/asm/irq.h +++ b/include/asm/irq.h @@ -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, diff --git a/include/linux/ext2_fs.h b/include/linux/ext2_fs.h index 168f978fddf1..28883831a31a 100644 --- a/include/linux/ext2_fs.h +++ b/include/linux/ext2_fs.h @@ -1,7 +1,9 @@ /* * 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 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 *, - const char *, ...) - __attribute__ ((format (printf, 3, 4))); +extern NORET_TYPE void ext2_panic (struct super_block *, const char *, + const char *, ...) + __attribute__ ((NORET_AND format (printf, 3, 4))); extern void ext2_warning (struct super_block *, const char *, const char *, ...) __attribute__ ((format (printf, 3, 4))); extern void ext2_put_super (struct super_block *); extern void ext2_write_super (struct super_block *); -extern int ext2_remount (struct super_block *, int *); +extern int ext2_remount (struct super_block *, int *, char *); extern struct super_block * ext2_read_super (struct super_block *,void *,int); extern void ext2_statfs (struct super_block *, struct statfs *); diff --git a/include/linux/ext2_fs_i.h b/include/linux/ext2_fs_i.h index 33fda9f9997c..777b37bd296f 100644 --- a/include/linux/ext2_fs_i.h +++ b/include/linux/ext2_fs_i.h @@ -1,7 +1,9 @@ /* * 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 */ diff --git a/include/linux/ext2_fs_sb.h b/include/linux/ext2_fs_sb.h index 5d58f0ce65d2..33af8388424c 100644 --- a/include/linux/ext2_fs_sb.h +++ b/include/linux/ext2_fs_sb.h @@ -1,7 +1,9 @@ /* * 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 */ diff --git a/include/linux/fs.h b/include/linux/fs.h index abc73b0a6692..83e1d8297619 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -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 { diff --git a/include/linux/net.h b/include/linux/net.h index 01e0633dff34..0806f928698d 100644 --- a/include/linux/net.h +++ b/include/linux/net.h @@ -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 */ diff --git a/include/linux/nfs.h b/include/linux/nfs.h index 97f14f232367..3cfbd1d12241 100644 --- a/include/linux/nfs.h +++ b/include/linux/nfs.h @@ -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 diff --git a/include/linux/sockios.h b/include/linux/sockios.h index 2090c33c9331..499b2190add5 100644 --- a/include/linux/sockios.h +++ b/include/linux/sockios.h @@ -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: */ diff --git a/net/inet/route.c b/net/inet/route.c index 2f20c9057b25..c914c7c19c75 100644 --- a/net/inet/route.c +++ b/net/inet/route.c @@ -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; diff --git a/tools/version.c b/tools/version.c index 190b93c3782c..1802cf545a46 100644 --- a/tools/version.c +++ b/tools/version.c @@ -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"; -- 2.39.5