]> git.neil.brown.name Git - history.git/commitdiff
Import 0.99.14j 0.99.14j
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:09:17 +0000 (15:09 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:09:17 +0000 (15:09 -0500)
29 files changed:
Makefile
drivers/sound/Makefile
drivers/sound/sb16_dsp.c
fs/ext2/acl.c
fs/ext2/balloc.c
fs/ext2/bitmap.c
fs/ext2/dcache.c
fs/ext2/dir.c
fs/ext2/file.c
fs/ext2/fsync.c
fs/ext2/ialloc.c
fs/ext2/inode.c
fs/ext2/ioctl.c
fs/ext2/namei.c
fs/ext2/super.c
fs/ext2/symlink.c
fs/ext2/truncate.c
fs/super.c
include/asm/io.h
include/asm/irq.h
include/linux/ext2_fs.h
include/linux/ext2_fs_i.h
include/linux/ext2_fs_sb.h
include/linux/fs.h
include/linux/net.h
include/linux/nfs.h
include/linux/sockios.h
net/inet/route.c
tools/version.c

index dbbe935b028dcbe3b1d8ea56c693c79be014c672..5761b0840551eecac4e7bf07e46ab8c88c785ecc 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 0.99
 PATCHLEVEL = 14
-ALPHA = i
+ALPHA = j
 
 all:   Version zImage
 
index 6b58c28422770211f01b11d210f734c376a23ff1..1f3760aae0951a6f460fecaf35ae45339624e561 100644 (file)
@@ -5,7 +5,7 @@
 #
 #
 
-VERSION                = 2.3
+VERSION                = 2.3b
 TARGET_OS      = linux
 
 .c.s:
index 4c799c061ec41f65f7848ceb7fc028c0b1ffdb4e..e8e25cc717155b9af584282d3825beb1e66057e7 100644 (file)
@@ -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;
 }
index 2103f8130d28f06b23c1e72e5df1205110623b5c..421fc11fc88d56c636634554a44b16e4e20d6d07 100644 (file)
@@ -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 <linux/errno.h>
 #include <linux/fs.h>
 #include <linux/ext2_fs.h>
-#include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/stat.h>
 
@@ -25,10 +26,14 @@ int ext2_permission (struct inode * inode, int mask)
 {
        unsigned short mode = inode->i_mode;
 
-       /* Special case, access is always granted for root */
+       /*
+        * Special case, access is always granted for root
+        */
        if (suser ())
                return 1;
-       /* If no ACL, checks using the file mode */
+       /*
+        * If no ACL, checks using the file mode
+        */
        else if (current->euid == inode->i_uid)
                mode >>= 6;
        else if (in_group_p (inode->i_gid))
index d5cf2d0394852b8d1c29f87d9ef2829820e66f43..96d0ab1953da8643326a6196ff4eae1374e55c59 100644 (file)
@@ -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 <linux/fs.h>
 #include <linux/ext2_fs.h>
-#include <linux/kernel.h>
 #include <linux/stat.h>
 #include <linux/sched.h>
 #include <linux/string.h>
@@ -39,6 +40,8 @@
                :"a" (0), "c" (size / 4), "D" ((long) (addr)) \
                :"cx", "di")
 
+#define in_range(b, first, len)                ((b) >= (first) && (b) <= (first) + (len) - 1)
+
 static inline int find_first_zero_bit (unsigned long * addr, unsigned size)
 {
        int res;
@@ -72,7 +75,9 @@ static inline int find_next_zero_bit (unsigned long * addr, int size,
        int set = 0, bit = offset & 31, res;
        
        if (bit) {
-               /* Look for zero in first byte */
+               /*
+                * Look for zero in first byte
+                */
                __asm__("
                        bsfl %1,%0
                        jne 1f
@@ -85,7 +90,9 @@ static inline int find_next_zero_bit (unsigned long * addr, int size,
                set = 32 - bit;
                p++;
        }
-       /* No zero yet, search remaining full bytes for a zero */
+       /*
+        * No zero yet, search remaining full bytes for a zero
+        */
        res = find_first_zero_bit (p, size - 32 * (p - addr));
        return (offset + set + res);
 }
@@ -109,32 +116,48 @@ static inline char * find_first_zero_byte (char * addr, int size)
        return res;
 }
 
-static void read_block_bitmap (struct super_block * sb,
-                              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",
index 70278ae05613f812a3affb43bbf5fa30ced951f2..1084da16d2e0318c3cdf8715f8807b393da8bc99 100644 (file)
@@ -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 <linux/fs.h>
index 8c3e69f756c6b3050d5730d4d3b616d8f57d551a..324ddaee43b0812f4eb046707f65be14b4585d9d 100644 (file)
@@ -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 <linux/fs.h>
 #include <linux/ext2_fs.h>
-#include <linux/kernel.h>
 #include <linux/string.h>
 
 #ifndef DONT_USE_DCACHE
index 24725fbb3baa9588dd38f80c99dba6626e7c5aa2..9cfff70a3dc1ea355ded6fe54bd3c3d9bca4d1d6 100644 (file)
@@ -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
  *
 
 #include <asm/segment.h>
 
+#include <linux/autoconf.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
 #include <linux/ext2_fs.h>
 #include <linux/sched.h>
 #include <linux/stat.h>
 
-#if 0
+#ifndef CONFIG_EXT2_FS_DIR_READ
 static int ext2_dir_read (struct inode * inode, struct file * filp,
                            char * buf, int count)
 {
        return -EISDIR;
 }
+#else
+int ext2_file_read (struct inode *, struct file *, char *, int);
 #endif
 
-/* static */ int ext2_file_read (struct inode *, struct file *, char *, int);
 static int ext2_readdir (struct inode *, struct file *, struct dirent *, int);
 
 static struct file_operations ext2_dir_operations = {
        NULL,                   /* lseek - default */
+#ifdef CONFIG_EXT2_FS_DIR_READ
        ext2_file_read,         /* read */
+#else
+       ext2_dir_read,          /* read */
+#endif
        NULL,                   /* write - bad */
        ext2_readdir,           /* readdir */
        NULL,                   /* select - default */
@@ -92,9 +100,9 @@ int ext2_check_dir_entry (char * function, struct inode * dir,
 static int ext2_readdir (struct inode * inode, struct file * filp,
                         struct dirent * dirent, int count)
 {
-       unsigned long offset;
-       int i;
-       struct buffer_head * bh;
+       unsigned long offset, blk;
+       int i, num;
+       struct buffer_head * bh, * tmp, * bha[16];
        struct ext2_dir_entry * de;
        struct super_block * sb;
        int err;
@@ -104,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;
                        }
index 4dd553dfcf298daa5d4279086e559f5e8fc48e65..e0e9e98cdb9f4b367e9c05aaa3bea6a9c3df58b9 100644 (file)
@@ -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
  *
 #include <asm/segment.h>
 #include <asm/system.h>
 
+#include <linux/autoconf.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
 #include <linux/ext2_fs.h>
 #include <linux/fcntl.h>
-#include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/stat.h>
 #include <linux/locks.h>
 #include <linux/fs.h>
 #include <linux/ext2_fs.h>
 
-/* static */ int ext2_file_read (struct inode *, struct file *, char *, int);
+#ifndef CONFIG_EXT2_FS_DIR_READ
+static
+#endif
+int ext2_file_read (struct inode *, struct file *, char *, int);
 static int ext2_file_write (struct inode *, struct file *, char *, int);
+static void ext2_release_file (struct inode *, struct file *);
 
 /*
  * We have mostly NULL's here: the current defaults are ok for
@@ -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);
+}
index 9a11cccf6d2685ed054911c49d55acb979828fbf..2f79c474988ed58af05e43c2ebbe21ee30e18d2c 100644 (file)
@@ -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++)
index 81053de8946ad7e6bd88c51aec15d704fbb0fffa..d44856b693ffba1cd2967425ba12685791d689fe 100644 (file)
@@ -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 <linux/fs.h>
 #include <linux/ext2_fs.h>
-#include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/stat.h>
 #include <linux/string.h>
@@ -59,28 +59,47 @@ static inline int find_first_zero_bit (unsigned long * addr, unsigned size)
        return res;
 }
 
-static void read_inode_bitmap (struct super_block * sb,
-                              unsigned long block_group,
-                              unsigned int bitmap_nr)
+static struct ext2_group_desc * get_group_desc (struct super_block * sb,
+                                               unsigned int block_group,
+                                               struct buffer_head ** bh)
 {
        unsigned long group_desc;
        unsigned long desc;
        struct ext2_group_desc * gdp;
-       struct buffer_head * bh;
+
+       if (block_group >= sb->u.ext2_sb.s_groups_count)
+               ext2_panic (sb, "get_group_desc",
+                           "block_group >= groups_count\n"
+                           "block_group = %d, groups_count = %lu",
+                           block_group, sb->u.ext2_sb.s_groups_count);
 
        group_desc = block_group / EXT2_DESC_PER_BLOCK(sb);
        desc = block_group % EXT2_DESC_PER_BLOCK(sb);
        if (!sb->u.ext2_sb.s_group_desc[group_desc])
-               ext2_panic (sb, "read_inode_bitmap",
+               ext2_panic (sb, "get_group_desc",
                            "Group descriptor not loaded\n"
-                           "block_group = %lu, group_desc = %lu, desc = %lu",
-                           block_group, 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",
index 92c8bdfc98fac1205c77698570c3ca4365564126..bbc1e52611266f118c6b0d7e813ec876bf579c49 100644 (file)
@@ -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
  *
 #include <linux/errno.h>
 #include <linux/fs.h>
 #include <linux/ext2_fs.h>
-#include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/stat.h>
 #include <linux/string.h>
 #include <linux/locks.h>
 
+#define clear_block(addr,size) \
+       __asm__("cld\n\t" \
+               "rep\n\t" \
+               "stosl" \
+               : \
+               :"a" (0), "c" (size / 4), "D" ((long) (addr)) \
+               :"cx", "di")
+
 void ext2_put_inode (struct inode * inode)
 {
+       ext2_discard_prealloc (inode);
        if (inode->i_nlink || inode->i_ino == EXT2_ACL_IDX_INO ||
            inode->i_ino == EXT2_ACL_DATA_INO)
                return;
@@ -48,6 +58,78 @@ static int block_bmap (struct buffer_head * bh, int nr)
        return tmp;
 }
 
+/* 
+ * ext2_discard_prealloc and ext2_alloc_block are atomic wrt. the
+ * superblock in the same manner as are ext2_free_blocks and
+ * ext2_new_block.  We just wait on the super rather than locking it
+ * here, since ext2_new_block will do the necessary locking and we
+ * can't block until then.
+ */
+void ext2_discard_prealloc (struct inode * inode)
+{
+#ifdef EXT2_PREALLOCATE
+       if (inode->u.ext2_i.i_prealloc_count) {
+               ext2_free_blocks (inode->i_sb,
+                                 inode->u.ext2_i.i_prealloc_block,
+                                 inode->u.ext2_i.i_prealloc_count);
+               inode->u.ext2_i.i_prealloc_count = 0;
+       }
+#endif
+}
+
+static int ext2_alloc_block (struct inode * inode, unsigned long goal)
+{
+#ifdef EXT2FS_DEBUG
+       static unsigned long alloc_hits = 0, alloc_attempts = 0;
+#endif
+       unsigned long result;
+       struct buffer_head * bh;
+
+       wait_on_super (inode->i_sb);
+
+#ifdef EXT2_PREALLOCATE
+       if (inode->u.ext2_i.i_prealloc_count &&
+           (goal == inode->u.ext2_i.i_prealloc_block ||
+            goal + 1 == inode->u.ext2_i.i_prealloc_block))
+       {               
+               result = inode->u.ext2_i.i_prealloc_block++;
+               inode->u.ext2_i.i_prealloc_count--;
+               ext2_debug ("preallocation hit (%lu/%lu).\n",
+                           ++alloc_hits, ++alloc_attempts);
+
+               /* It doesn't matter if we block in getblk() since
+                  we have already atomically allocated the block, and
+                  are only clearing it now. */
+               if (!(bh = getblk (inode->i_sb->s_dev, result,
+                                  inode->i_sb->s_blocksize))) {
+                       ext2_error (inode->i_sb, "ext2_alloc_block",
+                                   "cannot get block %lu", result);
+                       return 0;
+               }
+               clear_block (bh->b_data, inode->i_sb->s_blocksize);
+               bh->b_uptodate = 1;
+               bh->b_dirt = 1;
+               brelse (bh);
+       } else {
+               ext2_discard_prealloc (inode);
+               ext2_debug ("preallocation miss (%lu/%lu).\n",
+                           alloc_hits, ++alloc_attempts);
+               if (S_ISREG(inode->i_mode))
+                       result = ext2_new_block
+                               (inode->i_sb, goal,
+                                &inode->u.ext2_i.i_prealloc_count,
+                                &inode->u.ext2_i.i_prealloc_block);
+               else
+                       result = ext2_new_block (inode->i_sb, goal, 0, 0);
+       }
+#else
+       result = ext2_new_block (inode->i_sb, goal, 0, 0);
+#endif
+
+       return result;
+}
+
+
 int ext2_bmap (struct inode * inode, int block)
 {
        int i;
@@ -147,12 +229,12 @@ 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++)
index d01f9ef4f06f18f14b1f66940cc4d5524f7fbfd6..8c103ae4cbe216868232edb7dc025aaab97f9acc 100644 (file)
@@ -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 <asm/segment.h>
index ff049682647079653b97821402f781d07e52254a..d5a47b2a920f0e5c679cebd7636d1dce4b3067b0 100644 (file)
@@ -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 <linux/fs.h>
 #include <linux/ext2_fs.h>
 #include <linux/fcntl.h>
-#include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/stat.h>
 #include <linux/string.h>
  * truncated. Else they will be disallowed.
  */
 /* #define NO_TRUNCATE */
-       
+
+/*
+ * define how far ahead to read directories while searching them.
+ */
+#define NAMEI_RA_CHUNKS  2
+#define NAMEI_RA_BLOCKS  4
+#define NAMEI_RA_SIZE        (NAMEI_RA_CHUNKS * NAMEI_RA_BLOCKS)
+#define NAMEI_RA_INDEX(c,b)  (((c) * NAMEI_RA_BLOCKS) + (b))
+
 /*
  * NOTE! unlike strncmp, ext2_match returns 1 for success, 0 for failure.
  */
@@ -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,
index 63bce7edafb80c8a2edf635041893742eb5aaa11..766179f20fbdd56d964337b453c799b1eeb72ef5 100644 (file)
@@ -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 <linux/errno.h>
 #include <linux/fs.h>
 #include <linux/ext2_fs.h>
-#include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/stat.h>
 #include <linux/string.h>
@@ -41,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;
 }
index d6cff0ad5863078aaeddc5d9c0c7bc57b802f5db..a98ed66bbffbcb70350bb8f51e770b29ef720d09 100644 (file)
@@ -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
  *
index 9b67d35f5bed862b0c7fa6cefcf624a6db4d8395..aa366c71fe0f2eeebb03cc7026c88622a9f949e5 100644 (file)
@@ -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");
-}
index 089f6f386d3df2c994c3c85b071f70e0f595732f..dbbfb67a8559a5b3b040ea51655bca1bee92adf7 100644 (file)
@@ -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);
index c0cbcd16137c749988dc05cfda0c45ab629f6d36..b51095970a8f88d8958b4fe2ac0ff89c3edfab4c 100644 (file)
@@ -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
  */
 #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
index 191a6685ea68e8451a54f15debc77b3cf1e59ab2..b9d878105b82a850d5dfcbfdb78da082246e595a 100644 (file)
@@ -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,
index 168f978fddf12f7e175e90011f5aab54a2e0e079..28883831a31a965ff9576aaac70ae3a8eb196986 100644 (file)
@@ -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
  *
 #undef EXT2FS_PRE_02B_COMPAT
 
 /*
- * Define EXT2FS_PRE_04_COMPAT to convert ext2 fs prior to 0.4
+ * Define DONT_USE_DCACHE to inhibit the directory cache
  */
-#define EXT2_PRE_04_COMPAT
+#define DONT_USE_DCACHE
 
 /*
- * Define DONT_USE_DCACHE to inhibit the directory cache
+ * Define EXT2_PREALLOCATE to preallocate data blocks for expanding files
  */
-#define DONT_USE_DCACHE
+#define EXT2_PREALLOCATE
 
 /*
  * The second extended file system version
  */
-#define EXT2FS_DATE            "93/11/19"
-#define EXT2FS_VERSION         "0.4a"
+#define EXT2FS_DATE            "93/12/30"
+#define EXT2FS_VERSION         "0.4b"
 
 /*
  * Debug code
@@ -242,13 +244,33 @@ struct ext2_inode {
 /*
  * Mount flags
  */
-#define EXT2_MOUNT_CHECK               0x0001  /* Do some more checks */
-
+#define EXT2_MOUNT_CHECK_NORMAL                0x0001  /* Do some more checks */
+#define EXT2_MOUNT_CHECK_STRICT                0x0002  /* Do again more checks */
+#define EXT2_MOUNT_CHECK               (EXT2_MOUNT_CHECK_NORMAL | \
+                                        EXT2_MOUNT_CHECK_STRICT)
+#define EXT2_MOUNT_GRPID               0x0004  /* Create files with directory's group */
+#define EXT2_MOUNT_DEBUG               0x0008  /* Some debugging messages */
+#define EXT2_MOUNT_ERRORS_CONT         0x0010  /* Continue on errors */
+#define EXT2_MOUNT_ERRORS_RO           0x0020  /* Remount fs ro on errors */
+#define EXT2_MOUNT_ERRORS_PANIC                0x0040  /* Panic on errors */
+
+#define clear_opt(o, opt)              o &= ~EXT2_MOUNT_##opt
+#define set_opt(o, opt)                        o |= EXT2_MOUNT_##opt
+#define test_opt(sb, opt)              ((sb)->u.ext2_sb.s_mount_opt & \
+                                        EXT2_MOUNT_##opt)
 /*
  * Maximal mount counts between two filesystem checks
  */
 #define EXT2_DFL_MAX_MNT_COUNT         20      /* Allow 20 mounts */
 
+/*
+ * Behaviour when detecting errors
+ */
+#define EXT2_ERRORS_CONTINUE           1       /* Continue execution */
+#define EXT2_ERRORS_RO                 2       /* Remount fs read-only */
+#define EXT2_ERRORS_PANIC              3       /* Panic */
+#define EXT2_ERRORS_DEFAULT            EXT2_ERRORS_CONTINUE
+
 /*
  * Structure of the super block
  */
@@ -270,7 +292,9 @@ struct ext2_super_block {
        unsigned short s_max_mnt_count; /* Maximal mount count */
        unsigned short s_magic;         /* Magic signature */
        unsigned short s_state;         /* File system state */
-       unsigned long  s_reserved[241]; /* Padding to the end of the block */
+       unsigned short s_errors;        /* Behaviour when detecting errors */
+       unsigned short s_pad;
+       unsigned long  s_reserved[240]; /* Padding to the end of the block */
 };
 
 /*
@@ -300,12 +324,28 @@ struct ext2_dir_entry {
  * Function prototypes
  */
 
+/*
+ * Ok, these declarations are also in <linux/kernel.h> but none of the
+ * ext2 source programs needs to include it so they are duplicated here.
+ */
+#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5)
+# define NORET_TYPE    __volatile__
+# define ATTRIB_NORET  /**/
+# define NORET_AND     /**/
+#else
+# define NORET_TYPE    /**/
+# define ATTRIB_NORET  __attribute__((noreturn))
+# define NORET_AND     noreturn,
+#endif
+
 /* acl.c */
 extern int ext2_permission (struct inode *, int);
 
 /* balloc.c */
-extern int ext2_new_block (struct super_block *, unsigned long);
-extern void ext2_free_block (struct super_block *, unsigned long);
+extern int ext2_new_block (struct super_block *, unsigned long,
+                          unsigned long *, unsigned long *);
+extern void ext2_free_blocks (struct super_block *, unsigned long,
+                             unsigned long);
 extern unsigned long ext2_count_free_blocks (struct super_block *);
 extern void ext2_check_blocks_bitmap (struct super_block *);
 
@@ -351,6 +391,7 @@ extern void ext2_read_inode (struct inode *);
 extern void ext2_write_inode (struct inode *);
 extern void ext2_put_inode (struct inode *);
 extern int ext2_sync_inode (struct inode *);
+extern void ext2_discard_prealloc (struct inode *);
 
 /* ioctl.c */
 extern int ext2_ioctl (struct inode *, struct file *, unsigned int,
@@ -374,14 +415,14 @@ extern int ext2_rename (struct inode *, const char *, int,
 /* super.c */
 extern void ext2_error (struct super_block *, const char *, const char *, ...)
        __attribute__ ((format (printf, 3, 4)));
-extern volatile void ext2_panic (struct super_block *, const char *,
-                                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 *);
 
index 33fda9f9997cad4452816b3e1be468999eea3744..777b37bd296f2f51f7abdaa7cc3b4abc0e5177e5 100644 (file)
@@ -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 */
index 5d58f0ce65d22a02f697feb61d4a328eb18de005..33af8388424c16ede94ee9461a26f14fabf2c720 100644 (file)
@@ -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 */
index abc73b0a6692c84b6c89088fe202b7248ae0adaf..83e1d82976198e328a3669668edb47fdf300f4a5 100644 (file)
@@ -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 {
index 01e0633dff348380b3d7d83031f8709c4f0bff1f..0806f928698d4a4122970d2de6997fec52e8b1c6 100644 (file)
@@ -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           */
index 97f14f232367a45f6e34d88cc81a5d0d2e392879..3cfbd1d12241a9c844be9d32d056f9e329c16047 100644 (file)
 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
index 2090c33c93317c11de0a4aa57b183432addfdf28..499b2190add5bc9557cf7158ca2fd5f2ff9f7713 100644 (file)
@@ -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: */
 
index 2f20c9057b25a2d4f932760201309c8b1b097b39..c914c7c19c750a39420a4c4b62e8f3c13acd25a6 100644 (file)
@@ -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;
index 190b93c3782c616a9ae055e1422481a67bc5cfdc..1802cf545a468ee855d618a1a54038df18869ccb 100644 (file)
@@ -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";