--- linux-2.2.17pre9.ext3-0.0.2e/fs/buffer.c.~1~        Thu Jun 29 17:24:22 2000
+++ linux-2.2.17pre9.ext3-0.0.2e/fs/buffer.c    Thu Jun 29 20:41:30 2000
@@ -234,9 +234,9 @@
                       bh->b_count++;
                       next->b_count++;
                       bh->b_flushtime = 0;
-                       ll_rw_block(WRITE, 1, &bh);
                       J_ASSERT(!bh->b_transaction);
                       J_ASSERT(bh->b_jlist == 0);
+                       ll_rw_block(WRITE, 1, &bh);
                       bh->b_count--;
                       next->b_count--;
                       retry = 1;
@@ -1516,7 +1516,7 @@
               if (buffer_locked(p)) {
                       if (wait)
                               __wait_on_buffer(p);
-               } else if (buffer_dirty(p))
+               } else if (buffer_dirty(p) && !p->b_jlist)
                       ll_rw_block(WRITE, 1, &p);
       } while (tmp != bh);

@@ -1790,9 +1790,9 @@
#ifdef DEBUG
                                if(nlist != BUF_DIRTY) ncount++;
#endif
-                                ll_rw_block(WRITE, 1, &bh);
                                J_ASSERT(!bh->b_transaction);
                                J_ASSERT(bh->b_jlist == 0);
+                                ll_rw_block(WRITE, 1, &bh);
                                bh->b_count--;
                                next->b_count--;
                        }
@@ -1951,6 +1951,8 @@
                                         bh->b_count++;
                                         ndirty++;
                                         bh->b_flushtime = 0;
+                                         J_ASSERT(!bh->b_transaction);
+                                         J_ASSERT(bh->b_jlist == 0);
                                         if (major == LOOP_MAJOR) {
                                                 ll_rw_block(wrta_cmd,1, &bh);
                                                 wrta_cmd = WRITEA;
@@ -1959,8 +1961,6 @@
                                         }
                                         else
                                         ll_rw_block(WRITE, 1, &bh);
-                                         J_ASSERT(!bh->b_transaction);
-                                         J_ASSERT(bh->b_jlist == 0);
#ifdef DEBUG
                                         if(nlist != BUF_DIRTY) ncount++;
#endif
--- linux-2.2.17pre9.ext3-0.0.2e/fs/ext3/balloc.c.~1~   Thu Jun 29 17:24:22 2000
+++ linux-2.2.17pre9.ext3-0.0.2e/fs/ext3/balloc.c       Thu Jun 29 21:29:39 2000
@@ -214,7 +214,7 @@
        */
       if (sb->u.ext3_sb.s_loaded_block_bitmaps > 0 &&
           sb->u.ext3_sb.s_block_bitmap_number[0] == block_group &&
-           sb->u.ext3_sb.s_block_bitmap[block_group]) {
+           sb->u.ext3_sb.s_block_bitmap[0]) {
               return 0;
       }
       /*
@@ -611,6 +611,8 @@
               unlock_super (sb);
               return 0;
       }
+       if (!buffer_uptodate(bh))
+               wait_on_buffer(bh);

       /* @@@ This will eventually have to be a data-style operation,
           not metadata */
--- linux-2.2.17pre9.ext3-0.0.2e/fs/ext3/dir.c.~1~      Thu Jun 29 17:24:22 2000
+++ linux-2.2.17pre9.ext3-0.0.2e/fs/ext3/dir.c  Thu Jun 29 17:36:49 2000
@@ -196,15 +196,18 @@
                                * version stamp to detect whether or
                                * not the directory has been modified
                                * during the copy operation.
+                                * AV: It can't be modified, but it fscking
+                                * can be seeked by another process that shares
+                                * the descriptor.
                                */
-                               unsigned long version = inode->i_version;
+                               unsigned long version = filp->f_version;

                               error = filldir(dirent, de->name,
                                               de->name_len,
                                               filp->f_pos, le32_to_cpu(de->inode));
                               if (error)
                                       break;
-                               if (version != inode->i_version)
+                               if (version != filp->f_version)
                                       goto revalidate;
                               stored ++;
                       }
--- linux-2.2.17pre9.ext3-0.0.2e/fs/ext3/file.c.~1~     Thu Jun 29 17:24:22 2000
+++ linux-2.2.17pre9.ext3-0.0.2e/fs/ext3/file.c Wed Jul  5 14:50:32 2000
@@ -216,8 +216,7 @@
       needed = (count >> EXT3_BLOCK_SIZE_BITS(sb)) + 1;
       if (needed > EXT3_MAX_TRANS_DATA)
               needed = EXT3_MAX_TRANS_DATA;
-       handle = journal_start(EXT3_JOURNAL(inode),
-                              EXT3_DATA_TRANS_BLOCKS + needed);
+       handle = ext3_journal_start(inode, EXT3_DATA_TRANS_BLOCKS + needed);

       /* Check for overflow.. */

@@ -297,14 +296,13 @@
                       if (journal_extend(handle, needed)) {
                               /* Couldn't extend: OK, commit the current
                                * transaction and start a new one. */
-                               if (pos > inode->i_size)
-                                       inode->i_size = pos;
+                               if (pos > inode->u.ext3_i.i_disksize)
+                                       inode->u.ext3_i.i_disksize = pos;
                               inode->i_ctime = inode->i_mtime = CURRENT_TIME;
                               ext3_mark_inode_dirty(handle, inode);
-                               journal_stop(handle);
-                               handle = journal_start(EXT3_JOURNAL(inode),
-                                                      EXT3_DATA_TRANS_BLOCKS
-                                                      + needed);
+                               ext3_journal_stop(handle, inode);
+                               handle = ext3_journal_start
+                                   (inode, EXT3_DATA_TRANS_BLOCKS + needed);
                       }
               }

@@ -417,13 +415,16 @@
       if (filp->f_flags & O_SYNC)
               handle->h_sync = 1;

-       if (pos > inode->i_size)
+       if (pos > inode->i_size) {
               inode->i_size = pos;
+               inode->u.ext3_i.i_disksize = pos;
+       }
+
       inode->i_ctime = inode->i_mtime = CURRENT_TIME;
       *ppos = pos;
       ext3_mark_inode_dirty(handle, inode);
error_out:
-       journal_stop(handle);
+       ext3_journal_stop(handle, inode);
       return written;
}

--- linux-2.2.17pre9.ext3-0.0.2e/fs/ext3/fsync.c.~1~    Thu Jun 29 17:24:22 2000
+++ linux-2.2.17pre9.ext3-0.0.2e/fs/ext3/fsync.c        Tue Jul  4 15:00:23 2000
@@ -46,10 +46,21 @@
       if (!bh)
               return 0;
       if (wait && buffer_req(bh) && !buffer_uptodate(bh)) {
-               brelse (bh);
-               return -1;
+               /* There can be a parallel read(2) that started read-I/O
+                  on the buffer so we can't assume that there's been
+                  an I/O error without first waiting I/O completation. */
+               wait_on_buffer(bh);
+               if (!buffer_uptodate(bh))
+               {
+                       brelse (bh);
+                       return -1;
+               }
       }
       if (wait || !buffer_uptodate(bh) || !buffer_dirty(bh)) {
+               if (wait)
+                       /* when we return from fsync all the blocks
+                          must be _just_ stored on disk */
+                       wait_on_buffer(bh);
               brelse (bh);
               return 0;
       }
@@ -262,7 +273,7 @@
       struct inode *inode = dentry->d_inode;
       handle_t *handle;

-       handle = journal_start(EXT3_JOURNAL(inode), 1); /* @@@ Error? */
+       handle = ext3_journal_start(inode, 1); /* @@@ Error? */
       handle->h_sync = 1;

       if (S_ISLNK(inode->i_mode) && !(inode->i_blocks))
@@ -289,6 +300,6 @@

skip:
       err |= ext3_mark_inode_dirty (handle, inode);
-       journal_stop(handle);
+       ext3_journal_stop(handle, inode);
       return err ? -EIO : 0;
}
--- linux-2.2.17pre9.ext3-0.0.2e/fs/ext3/ialloc.c.~1~   Thu Jun 29 17:24:22 2000
+++ linux-2.2.17pre9.ext3-0.0.2e/fs/ext3/ialloc.c       Fri Jun 30 11:06:36 2000
@@ -270,21 +270,6 @@
}

/*
- * This function increments the inode version number
- *
- * This may be used one day by the NFS server
- */
-static void inc_inode_version (struct inode * inode,
-                              struct ext3_group_desc *gdp,
-                              int mode)
-{
-       inode->u.ext3_i.i_version++;
-       mark_inode_dirty(inode);
-
-       return;
-}
-
-/*
 * 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
 * free space and a low directory-to-inode ratio; if that fails, then of
@@ -497,13 +482,15 @@
       inode->u.ext3_i.i_file_acl = 0;
       inode->u.ext3_i.i_dir_acl = 0;
       inode->u.ext3_i.i_dtime = 0;
+       INIT_LIST_HEAD(&inode->u.ext3_i.i_orphan);
       inode->u.ext3_i.i_block_group = i;
       inode->i_op = NULL;
       if (inode->u.ext3_i.i_flags & EXT3_SYNC_FL)
               inode->i_flags |= MS_SYNCHRONOUS;
       insert_inode_hash(inode);
+       inode->i_generation = inode_generation_count++;
+       inode->u.ext3_i.i_version = inode->i_generation;
       ext3_mark_inode_dirty(handle, inode);
-       inc_inode_version (inode, gdp, mode);

       unlock_super (sb);
       if(DQUOT_ALLOC_INODE(sb, inode)) {
@@ -516,6 +503,51 @@
       ext3_debug ("allocating inode %lu\n", inode->i_ino);

       *err = 0;
+       return inode;
+}
+
+/* Verify that we are loading a valid orphan from disk */
+struct inode *ext3_orphan_get (struct super_block * sb, ino_t ino)
+{
+       ino_t max_ino = le32_to_cpu(EXT3_SB(sb)->s_es->s_inodes_count);
+       unsigned long block_group;
+       unsigned long bit;
+       int bitmap_nr;
+       struct buffer_head *bh;
+       struct inode *inode = NULL;
+
+       /* Error cases - e2fsck has already cleaned up for us */
+       if (ino > max_ino) {
+               ext3_warning(sb, __FUNCTION__,
+                            "bad orphan ino %ld!  e2fsck was run?\n", ino);
+               return NULL;
+       }
+
+       block_group = (ino - 1) / EXT3_INODES_PER_GROUP(sb);
+       bit = (ino - 1) % EXT3_INODES_PER_GROUP(sb);
+       if ((bitmap_nr = load_inode_bitmap(sb, block_group)) < 0 ||
+           !(bh = EXT3_SB(sb)->s_inode_bitmap[bitmap_nr])) {
+               ext3_warning(sb, __FUNCTION__,
+                            "inode bitmap error for orphan %ld\n", ino);
+               return NULL;
+       }
+
+       /* Having the inode bit set should be a 100% indicator that this
+        * is a valid orphan (no e2fsck run on fs).  Orphans also include
+        * inodes that were being truncated, so we can't check i_nlink==0.
+        */
+       if (!ext3_test_bit(bit, bh->b_data) || !(inode = iget(sb, ino)) ||
+           is_bad_inode(inode) || NEXT_ORPHAN(inode) > max_ino) {
+               ext3_warning(sb, __FUNCTION__,
+                            "bad orphan inode %ld!  e2fsck was run?\n", ino);
+
+               /* Avoid freeing blocks if we got a bad deleted inode */
+               if (inode && inode->i_nlink == 0)
+                       inode->i_blocks = 0;
+               iput(inode);
+               return NULL;
+       }
+
       return inode;
}

--- linux-2.2.17pre9.ext3-0.0.2e/fs/ext3/inode.c.~1~    Thu Jun 29 17:24:22 2000
+++ linux-2.2.17pre9.ext3-0.0.2e/fs/ext3/inode.c        Wed Jul  5 14:48:31 2000
@@ -42,6 +42,40 @@
}

/*
+ * ext3_orphan_del() removes an unlinked or truncated inode from the list
+ * of such inodes stored on disk, because it is finally being cleaned up.
+ */
+void ext3_orphan_del(handle_t *handle, struct inode *inode)
+{
+       struct list_head *prev = inode->u.ext3_i.i_orphan.prev;
+       struct ext3_sb_info *sbi = EXT3_SB(inode->i_sb);
+       ino_t ino_next = NEXT_ORPHAN(inode);
+
+       if (list_empty(&inode->u.ext3_i.i_orphan))
+               return;
+
+       jfs_debug(4, "remove inode %ld from orphan list\n", inode->i_ino);
+       lock_super(inode->i_sb);
+       list_del(&inode->u.ext3_i.i_orphan);
+
+       if (prev == &sbi->s_orphan) {
+               jfs_debug(4, "superblock will point to %ld\n", ino_next);
+               journal_get_write_access(handle, sbi->s_sbh);
+               sbi->s_es->s_last_orphan = cpu_to_le32(ino_next);
+               journal_dirty_metadata(handle, sbi->s_sbh);
+       } else {
+               struct inode *i_prev =
+                       list_entry(prev, struct inode, u.ext3_i.i_orphan);
+
+               jfs_debug(4, "orphan inode %ld will point to %ld\n",
+                         i_prev->i_ino, ino_next);
+               NEXT_ORPHAN(i_prev) = ino_next;
+               ext3_mark_inode_dirty(handle, i_prev);
+       }
+       unlock_super(inode->i_sb);
+}
+
+/*
 * Called at the last iput() if i_nlink is zero.
 */
void ext3_delete_inode (struct inode * inode)
@@ -51,19 +85,24 @@
       if (inode->i_ino == EXT3_ACL_IDX_INO ||
           inode->i_ino == EXT3_ACL_DATA_INO)
               return;
-       inode->u.ext3_i.i_dtime = CURRENT_TIME;

-       handle = journal_start(EXT3_JOURNAL(inode),
-                              EXT3_DELETE_TRANS_BLOCKS);
+       /* When we delete an inode, we increment its i_version. If it
+          is ever read in from disk again, it will have a different
+          i_version. */
+       inode->u.ext3_i.i_version++;
+
+       handle = ext3_journal_start(inode, EXT3_DELETE_TRANS_BLOCKS);

       if (IS_SYNC(inode))
               handle->h_sync = 1;
-       ext3_mark_inode_dirty(handle, inode);
       inode->i_size = 0;
       if (inode->i_blocks)
               ext3_truncate (inode);
-       ext3_free_inode (handle, inode);
-       journal_stop(handle);
+       ext3_orphan_del(handle, inode);
+       inode->u.ext3_i.i_dtime = CURRENT_TIME;
+       ext3_mark_inode_dirty(handle, inode);
+       ext3_free_inode(handle, inode);
+       ext3_journal_stop(handle, inode);
}

#define inode_bmap(inode, nr) ((inode)->u.ext3_i.i_data[(nr)])
@@ -129,6 +168,8 @@
                                   "cannot get block %lu", result);
                       return 0;
               }
+               if (!buffer_uptodate(bh))
+                       wait_on_buffer(bh);
               /* @@@ Once we start journaling data separately, this
                   needs to become dependent on the type of inode we
                   are allocating inside */
@@ -579,10 +620,13 @@
                       << 32;
#endif
       }
+       inode->u.ext3_i.i_disksize = inode->i_size;
       inode->u.ext3_i.i_version = le32_to_cpu(iloc.raw_inode->i_version);
+       inode->i_generation = inode->u.ext3_i.i_version;
       inode->u.ext3_i.i_block_group = iloc.block_group;
       inode->u.ext3_i.i_next_alloc_block = 0;
       inode->u.ext3_i.i_next_alloc_goal = 0;
+       INIT_LIST_HEAD(&inode->u.ext3_i.i_orphan);
       if (inode->u.ext3_i.i_prealloc_count)
               ext3_error (inode->i_sb, "ext3_read_inode",
                           "New inode has non-zero prealloc count!");
@@ -656,7 +700,7 @@
       raw_inode->i_uid = cpu_to_le16(inode->i_uid);
       raw_inode->i_gid = cpu_to_le16(inode->i_gid);
       raw_inode->i_links_count = cpu_to_le16(inode->i_nlink);
-       raw_inode->i_size = cpu_to_le32(inode->i_size);
+       raw_inode->i_size = cpu_to_le32(inode->u.ext3_i.i_disksize);
       raw_inode->i_atime = cpu_to_le32(inode->i_atime);
       raw_inode->i_ctime = cpu_to_le32(inode->i_ctime);
       raw_inode->i_mtime = cpu_to_le32(inode->i_mtime);
@@ -674,7 +718,7 @@
               raw_inode->i_size_high =
                       cpu_to_le32(inode->u.ext3_i.i_high_size);
#else
-               raw_inode->i_size_high = cpu_to_le32(inode->i_size >> 32);
+               raw_inode->i_size_high = cpu_to_le32(inode->u.ext3_i.i_disksize >> 32);
#endif
       }
       raw_inode->i_version = cpu_to_le32(inode->u.ext3_i.i_version);
@@ -813,14 +857,14 @@
                               struct buffer_head *bh = sb->u.ext3_sb.s_sbh;

                               /* @@@ Error, null handle? */
-                               handle = journal_start(EXT3_JOURNAL(inode), 1);
+                               handle = ext3_journal_start(inode, 1);

                               /* If this is the first large file
                                * created, add a flag to the superblock */
                               es->s_feature_ro_compat |=
                               cpu_to_le32(EXT3_FEATURE_RO_COMPAT_LARGE_FILE);
                               journal_dirty_metadata(handle, bh); /*@@@err*/
-                               journal_stop(handle);
+                               ext3_journal_stop(handle, inode);
                       }
               }
#endif
@@ -835,7 +879,7 @@
        * required is one. */

       /* @@@ Error, null handle? */
-       handle = journal_start(EXT3_JOURNAL(inode), 1);
+       handle = ext3_journal_start(inode, 1);
       retval = ext3_reserve_inode_write(handle, inode, &iloc);
       if (retval)
               goto out_stop;
@@ -877,7 +921,7 @@
       retval = ext3_mark_iloc_dirty(handle, inode, &iloc);

out_stop:
-       journal_stop(handle);
+       ext3_journal_stop(handle, inode);
out:
       return retval;
}
--- linux-2.2.17pre9.ext3-0.0.2e/fs/ext3/ioctl.c.~1~    Thu Jun 29 17:24:22 2000
+++ linux-2.2.17pre9.ext3-0.0.2e/fs/ext3/ioctl.c        Thu Jun 29 21:36:18 2000
@@ -77,6 +77,7 @@
               if (get_user(inode->u.ext3_i.i_version, (int *) arg))
                       return -EFAULT;
               inode->i_ctime = CURRENT_TIME;
+               inode->i_generation = inode->u.ext3_i.i_version;
               mark_inode_dirty(inode);
               return 0;
       default:
--- linux-2.2.17pre9.ext3-0.0.2e/fs/ext3/namei.c.~1~    Thu Jun 29 17:24:22 2000
+++ linux-2.2.17pre9.ext3-0.0.2e/fs/ext3/namei.c        Tue Jul  4 15:35:08 2000
@@ -373,8 +373,7 @@
       handle_t *handle;
       int err = -EIO;

-       handle = journal_start(EXT3_JOURNAL(dir),
-                              EXT3_DATA_TRANS_BLOCKS + 3);
+       handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS + 3);

       /*
        * N.B. Several error exits in ext3_new_inode don't set err.
@@ -406,7 +405,7 @@
       d_instantiate(dentry, inode);

out:
-       journal_stop(handle);
+       ext3_journal_stop(handle, inode);
       return err;
}

@@ -418,8 +417,7 @@
       int err = -EIO;
       handle_t *handle = 0;

-       handle = journal_start(EXT3_JOURNAL(dir),
-                              EXT3_DATA_TRANS_BLOCKS + 3);
+       handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS + 3);

       inode = ext3_new_inode (handle, dir, mode, &err);
       if (!inode)
@@ -438,6 +436,10 @@
               if (EXT3_HAS_INCOMPAT_FEATURE(dir->i_sb,
                                             EXT3_FEATURE_INCOMPAT_FILETYPE))
                       de->file_type = EXT3_FT_REG_FILE;
+       } else if (S_ISSOCK(inode->i_mode)) {
+               if (EXT3_HAS_INCOMPAT_FEATURE(dir->i_sb,
+                                             EXT3_FEATURE_INCOMPAT_FILETYPE))
+                       de->file_type = EXT3_FT_SOCK;
       } else if (S_ISCHR(inode->i_mode)) {
               inode->i_op = &chrdev_inode_operations;
               if (EXT3_HAS_INCOMPAT_FEATURE(dir->i_sb,
@@ -463,7 +465,7 @@
       d_instantiate(dentry, inode);
       brelse(bh);
out_stop:
-       journal_stop(handle);
+       ext3_journal_stop(handle, inode);
       return err;

out_no_entry:
@@ -485,8 +487,7 @@
       if (dir->i_nlink >= EXT3_LINK_MAX)
               goto out;

-       handle = journal_start(EXT3_JOURNAL(dir),
-                              EXT3_DATA_TRANS_BLOCKS + 4);
+       handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS + 4);
       err = -EIO;
       inode = ext3_new_inode (handle, dir, S_IFDIR, &err);
       if (!inode)
@@ -545,7 +546,7 @@
       err = 0;

out_stop:
-       journal_stop(handle);
+       ext3_journal_stop(handle, inode);
out:
       return err;

@@ -628,8 +629,7 @@
       struct ext3_dir_entry_2 * de;
       handle_t *handle;

-       handle = journal_start(EXT3_JOURNAL(dir),
-                              EXT3_DELETE_TRANS_BLOCKS);
+       handle = ext3_journal_start(dir, EXT3_DELETE_TRANS_BLOCKS);

       retval = -ENOENT;
       bh = ext3_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de);
@@ -669,11 +669,41 @@
               handle->h_sync = 1;

end_rmdir:
-       journal_stop(handle);
+       ext3_journal_stop(handle, dir);
       brelse (bh);
       return retval;
}

+/* ext3_orphan_add() links a unlinked or truncated inode into a list of
+ * such inodes, starting at the superblock, in case we crash before the
+ * file is closed/deleted, or in case the inode truncate spans multiple
+ * transactions and the last transaction is not recovered after a crash.
+ *
+ * At filesystem recovery time, we walk this list deleting unlinked
+ * inodes and truncating linked inodes in ext3_orphan_cleanup().
+ */
+void ext3_orphan_add(handle_t *handle, struct inode *inode)
+{
+       struct super_block *sb = inode->i_sb;
+
+       lock_super(sb);
+       if (!list_empty(&inode->u.ext3_i.i_orphan)) {
+               unlock_super(sb);
+               return;
+       }
+       journal_get_write_access(handle, sb->u.ext3_sb.s_sbh);
+       NEXT_ORPHAN(inode) = le32_to_cpu(EXT3_SB(sb)->s_es->s_last_orphan);
+       EXT3_SB(sb)->s_es->s_last_orphan = cpu_to_le32(inode->i_ino);
+       journal_dirty_metadata(handle, sb->u.ext3_sb.s_sbh);
+       list_add(&inode->u.ext3_i.i_orphan, &EXT3_SB(sb)->s_orphan);
+       ext3_mark_inode_dirty(handle, inode);
+       unlock_super(sb);
+
+       jfs_debug(4, "superblock will point to %ld\n", inode->i_ino);
+       jfs_debug(4, "orphan inode %ld will point to %d\n",
+                 inode->i_ino, NEXT_ORPHAN(inode));
+}
+
int ext3_unlink(struct inode * dir, struct dentry *dentry)
{
       int retval;
@@ -682,8 +712,7 @@
       struct ext3_dir_entry_2 * de;
       handle_t *handle;

-       handle = journal_start(EXT3_JOURNAL(dir),
-                              EXT3_DELETE_TRANS_BLOCKS);
+       handle = ext3_journal_start(dir, EXT3_DELETE_TRANS_BLOCKS);

       retval = -ENOENT;
       bh = ext3_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de);
@@ -713,13 +742,15 @@
       dir->u.ext3_i.i_flags &= ~EXT3_BTREE_FL;
       ext3_mark_inode_dirty(handle, dir);
       inode->i_nlink--;
+       if (!inode->i_nlink)
+               ext3_orphan_add(handle, inode);
       ext3_mark_inode_dirty(handle, inode);
       inode->i_ctime = dir->i_ctime;
       retval = 0;
       d_delete(dentry);       /* This also frees the inode */

end_unlink:
-       journal_stop(handle);
+       ext3_journal_stop(handle, dir);
       brelse (bh);
       return retval;
}
@@ -734,8 +765,7 @@
       char c;
       handle_t *handle;

-       handle = journal_start(EXT3_JOURNAL(dir),
-                              EXT3_DATA_TRANS_BLOCKS + 5);
+       handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS + 5);

       if (!(inode = ext3_new_inode (handle, dir, S_IFLNK, &err)))
               goto out;
@@ -788,7 +818,7 @@
       d_instantiate(dentry, inode);
       err = 0;
out:
-       journal_stop(handle);
+       ext3_journal_stop(handle, dir);
       return err;

out_no_entry:
@@ -813,8 +843,7 @@
       if (inode->i_nlink >= EXT3_LINK_MAX)
               return -EMLINK;

-       handle = journal_start(EXT3_JOURNAL(dir),
-                              EXT3_DATA_TRANS_BLOCKS);
+       handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS);

       bh = ext3_add_entry (handle, dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
       if (!bh)
@@ -829,6 +858,8 @@
                       de->file_type = EXT3_FT_DIR;
               else if (S_ISLNK(inode->i_mode))
                       de->file_type = EXT3_FT_SYMLINK;
+               else if (S_ISSOCK(inode->i_mode))
+                       de->file_type = EXT3_FT_SOCK;
               else if (S_ISCHR(inode->i_mode))
                       de->file_type = EXT3_FT_CHRDEV;
               else if (S_ISBLK(inode->i_mode))
@@ -847,7 +878,7 @@
       d_instantiate(dentry, inode);
       err = 0;
out:
-       journal_stop(handle);
+       ext3_journal_stop(handle, dir);
       return err;
}

@@ -870,8 +901,7 @@

       old_bh = new_bh = dir_bh = NULL;

-       handle = journal_start(EXT3_JOURNAL(old_dir),
-                              2 * EXT3_DATA_TRANS_BLOCKS + 2);
+       handle = ext3_journal_start(old_dir, 2 * EXT3_DATA_TRANS_BLOCKS + 2);

       old_bh = ext3_find_entry (old_dir, old_dentry->d_name.name, old_dentry->d_name.len, &old_de);
       /*
@@ -972,6 +1002,6 @@
       brelse (dir_bh);
       brelse (old_bh);
       brelse (new_bh);
-       journal_stop(handle);
+       ext3_journal_stop(handle, old_dir);
       return retval;
}
--- linux-2.2.17pre9.ext3-0.0.2e/fs/ext3/super.c.~1~    Thu Jun 29 17:24:22 2000
+++ linux-2.2.17pre9.ext3-0.0.2e/fs/ext3/super.c        Tue Jul  4 23:47:07 2000
@@ -44,6 +44,8 @@
static void ext3_commit_super (struct super_block * sb,
                              struct ext3_super_block * es,
                              int sync);
+static void ext3_mark_recovery_complete(struct super_block * sb,
+                                       struct ext3_super_block * es);

void ext3_error (struct super_block * sb, const char * function,
                const char * fmt, ...)
@@ -137,6 +139,8 @@
                       brelse (EXT3_SB(sb)->s_block_bitmap[i]);
       brelse (EXT3_SB(sb)->s_sbh);

+       J_ASSERT (list_empty(&EXT3_SB(sb)->s_orphan));
+
       MOD_DEC_USE_COUNT;
       return;
}
@@ -197,7 +201,7 @@
               else if (!strcmp (this_char, "errors")) {
                       if (!value || !*value) {
                               printk ("EXT3-fs: the errors option requires "
-                                       "an argument");
+                                       "an argument\n");
                               return 0;
                       }
                       if (!strcmp (value, "continue")) {
@@ -414,6 +418,73 @@
       return 1;
}

+/* ext3_orphan_cleanup() walks a singly-linked list of inodes (starting at
+ * the superblock) which were deleted from all directories, but held open by
+ * a process at the time of a crash.  We walk the list and try to delete these
+ * inodes at recovery time (only with a read-write filesystem).
+ *
+ * In order to keep the orphan inode chain consistent during traversal (in
+ * case of crash during recovery), we link each inode into the superblock
+ * orphan list_head and handle it the same way as an inode deletion during
+ * normal operation (which journals the operations for us).
+ *
+ * We only do an iget() and an iput() on each inode, which is very safe if we
+ * accidentally point at an in-use or already deleted inode.  The worst that
+ * can happen in this case is that we get a "bit already cleared" message from
+ * ext3_free_inode().  The only reason we would point at a wrong inode is if
+ * e2fsck was run on this filesystem, and it must have already done the orphan
+ * inode cleanup for us, so we can safely abort without any further action.
+ */
+static void ext3_orphan_cleanup (struct super_block * sb,
+                                struct ext3_super_block * es)
+{
+       unsigned int s_flags = sb->s_flags;
+       int nr_orphans = 0, nr_truncates = 0;
+       if (!es->s_last_orphan) {
+               jfs_debug(4, "no orphan inodes to clean up\n");
+               return;
+       }
+
+       if (s_flags & MS_RDONLY) {
+               printk(KERN_INFO "EXT3-fs: %s: orphan cleanup on read-only fs\n",
+                      kdevname(sb->s_dev));
+               sb->s_flags &= ~MS_RDONLY;
+       }
+
+       while (es->s_last_orphan) {
+               struct inode *inode;
+
+               if (!(inode =
+                     ext3_orphan_get(sb, le32_to_cpu(es->s_last_orphan)))) {
+                       es->s_last_orphan = 0;
+                       break;
+               }
+
+               list_add(&inode->u.ext3_i.i_orphan, &EXT3_SB(sb)->s_orphan);
+               if (inode->i_nlink) {
+                       jfs_debug(2, "truncating inode %ld to %ld bytes\n",
+                                 inode->i_ino, inode->i_size);
+                       ext3_truncate(inode);
+                       nr_truncates++;
+               } else {
+                       jfs_debug(2, "deleting unreferenced inode %ld\n",
+                                 inode->i_ino);
+                       nr_orphans++;
+               }
+               iput(inode);  /* The delete magic happens here! */
+       }
+
+#define PLURAL(x) (x), ((x)==1) ? "" : "s"
+
+       if (nr_orphans)
+               printk(KERN_INFO "EXT3-fs: %s: %d orphan inode%s deleted\n",
+                      kdevname(sb->s_dev), PLURAL(nr_orphans));
+       if (nr_truncates)
+               printk(KERN_INFO "EXT3-fs: %s: %d truncate%s cleaned up\n",
+                      kdevname(sb->s_dev), PLURAL(nr_truncates));
+       sb->s_flags = s_flags; /* Restore MS_RDONLY status */
+}
+
#define log2(n) ffz(~(n))

struct super_block * ext3_read_super (struct super_block * sb, void * data,
@@ -670,6 +741,7 @@
        */
       sb->s_dev = dev;
       sb->s_op = &ext3_sops;
+       INIT_LIST_HEAD(&sb->u.ext3_sb.s_orphan); /* unlinked but open files */
       unlock_super (sb);

       err = 0;
@@ -699,7 +771,10 @@
       sb->s_root = d_alloc_root(iget(sb, EXT3_ROOT_INO), NULL);
       if (!sb->s_root)
               goto error_out;
-       ext3_setup_super (sb, es);
+       ext3_setup_super(sb, es);
+       ext3_orphan_cleanup(sb, es);
+       ext3_mark_recovery_complete(sb, es);
+       printk (KERN_INFO "EXT3-fs: recovery complete.\n");
       return sb;

 error_out:
@@ -755,7 +830,7 @@
        * can get read-write access to the device.
        */

-       if (es->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER) {
+       if (es->s_feature_incompat & cpu_to_le32(EXT3_FEATURE_INCOMPAT_RECOVER)) {
               if (sb->s_flags & MS_RDONLY) {
                       printk(KERN_ERR "EXT3-fs: WARNING: recovery required on readonly filesystem.\n");
                       if (is_read_only(sb->s_dev)) {
@@ -785,21 +860,6 @@
       }

       EXT3_SB(sb)->s_journal = journal;
-
-       /*
-        * Have we just finished recovery?  If so, and if we are
-        * mounting the filesystem readonly, then we will end up with a
-        * consistent fs on disk.  Record that fact if so.
-        */
-
-       if (le32_to_cpu(es->s_feature_incompat) & EXT3_FEATURE_INCOMPAT_RECOVER) {
-               printk (KERN_INFO "EXT3-fs: recovery complete.\n");
-               if (sb->s_flags & MS_RDONLY) {
-                       es->s_feature_incompat &= ~(cpu_to_le32(EXT3_FEATURE_INCOMPAT_RECOVER));
-                       ext3_commit_super(sb, es, 1);
-               }
-       }
-
       return 0;
}

@@ -848,13 +908,33 @@
{
       es->s_wtime = cpu_to_le32(CURRENT_TIME);
       mark_buffer_dirty(sb->u.ext3_sb.s_sbh, 1);
-       sb->s_dirt = 0;
       if (sync) {
               ll_rw_block(WRITE, 1, &sb->u.ext3_sb.s_sbh);
               wait_on_buffer(sb->u.ext3_sb.s_sbh);
       }
}

+
+/*
+ * Have we just finished recovery?  If so, and if we are mounting the
+ * filesystem readonly, then we will end up with a consistent fs on
+ * disk.  Record that fact if so.
+ */
+static void ext3_mark_recovery_complete(struct super_block * sb,
+                                       struct ext3_super_block * es)
+{
+       journal_flush(EXT3_SB(sb)->s_journal);
+       if (EXT3_HAS_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER)) {
+               if (sb->s_flags & MS_RDONLY) {
+                       EXT3_SB(sb)->s_feature_incompat &= ~EXT3_FEATURE_INCOMPAT_RECOVER;
+                       es->s_feature_incompat = cpu_to_le32(EXT3_SB(sb)->s_feature_incompat);
+                       es->s_mtime = cpu_to_le32(CURRENT_TIME);
+                       ext3_commit_super(sb, es, 1);
+                       sb->s_dirt = 0;
+               }
+       }
+}
+
/*
 * In the second extended file system, it is not necessary to
 * write the super block since we use a mapping of the
@@ -868,20 +948,22 @@

void ext3_write_super (struct super_block * sb)
{
-       struct ext3_super_block * es;
+       tid_t wait_tid;

+       sb->s_dirt = 0;
+
       if (!(sb->s_flags & MS_RDONLY)) {
               journal_t *journal;

               journal = EXT3_SB(sb)->s_journal;
-               es = sb->u.ext3_sb.s_es;

-               if (journal->j_running_transaction)
+               if (journal->j_running_transaction) {
+                       wait_tid = journal->j_running_transaction->t_tid;
                       log_start_commit(journal, journal->j_running_transaction);
-               if (journal->j_committing_transaction)
+                       log_wait_commit(journal, wait_tid);
+               } else if (journal->j_committing_transaction)
                       log_wait_commit(journal, journal->j_committing_transaction->t_tid);
       }
-       sb->s_dirt = 0;
}

int ext3_remount (struct super_block * sb, int * flags, char * data)
@@ -912,7 +994,6 @@
                * to disable replay of the journal when we next remount
                */
               sb->s_flags |= MS_RDONLY;
-               journal_flush(EXT3_SB(sb)->s_journal);

               /*
                * OK, test if we are remounting a valid rw partition
@@ -923,11 +1004,7 @@
                   (sb->u.ext3_sb.s_mount_state & EXT3_VALID_FS))
                       es->s_state = cpu_to_le16(sb->u.ext3_sb.s_mount_state);

-               es->s_feature_incompat &= cpu_to_le32(~EXT3_FEATURE_INCOMPAT_RECOVER);
-               es->s_mtime = cpu_to_le32(CURRENT_TIME);
-               mark_buffer_dirty(sb->u.ext3_sb.s_sbh, 1);
-               sb->s_dirt = 1;
-               ext3_commit_super (sb, es, 1);
+               ext3_mark_recovery_complete(sb, es);
       }
       else {
               /*
@@ -938,6 +1015,7 @@
               sb->u.ext3_sb.s_mount_state = le16_to_cpu(es->s_state);
               sb->s_flags &= ~MS_RDONLY;
               ext3_setup_super (sb, es);
+               sb->s_dirt = 1;
       }
       return 0;
}
--- linux-2.2.17pre9.ext3-0.0.2e/fs/ext3/truncate.c.~1~ Thu Jun 29 17:24:22 2000
+++ linux-2.2.17pre9.ext3-0.0.2e/fs/ext3/truncate.c     Wed Jul  5 14:53:52 2000
@@ -136,8 +136,7 @@
       if (needed > EXT3_MAX_TRANS_DATA)
               needed = EXT3_MAX_TRANS_DATA;

-       return journal_start(EXT3_JOURNAL(inode),
-                            EXT3_DATA_TRANS_BLOCKS + needed);
+       return ext3_journal_start(inode, EXT3_DATA_TRANS_BLOCKS + needed);
}

static int extend_transaction(handle_t *handle, struct inode *inode)
@@ -487,6 +486,19 @@

       handle = start_transaction(inode);

+       /* Add inode to orphan list, so that if this truncate spans multiple
+        * transactions, and we crash and don't recover the last transaction
+        * we will resume the truncate when the filesystem recovers.
+        */
+       ext3_orphan_add(handle, inode);
+       ext3_mark_inode_dirty(handle, inode);
+
+       /* The orphan list will now protect us from a crash before the
+        * truncate completes, so it is finally safe to propagate the
+        * new inode size (held for now in i_size) into the on-disk
+        * inode. */
+       inode->u.ext3_i.i_disksize = inode->i_size;
+
       while (1) {
               retry = trunc_direct(handle, inode);
               retry |= trunc_indirect (handle, inode,
@@ -500,7 +512,7 @@
               retry |= trunc_tindirect (handle, inode);
               if (!retry)
                       break;
-               journal_stop(handle);
+               ext3_journal_stop(handle, inode);
               current->counter = 0;
               run_task_queue(&tq_disk);
               current->policy |= SCHED_YIELD;
@@ -528,6 +540,10 @@
               }
       }
       inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+       if (inode->i_nlink) {
+               ext3_orphan_del(handle, inode);
+               NEXT_ORPHAN(inode) = 0;
+       }
       ext3_mark_inode_dirty(handle, inode);
-       journal_stop(handle);
+       ext3_journal_stop(handle, inode);
}
--- linux-2.2.17pre9.ext3-0.0.2e/fs/jfs/commit.c.~1~    Thu Jun 29 17:24:22 2000
+++ linux-2.2.17pre9.ext3-0.0.2e/fs/jfs/commit.c        Thu Jun 29 23:27:37 2000
@@ -38,7 +38,7 @@
       int blocknr;
       char *tagp = NULL;
       journal_header_t *header;
-       journal_block_tag_t *tag = NULL, *last_tag;
+       journal_block_tag_t *tag = NULL;
       int space_left = 0;
       int first_tag = 0;
       int tag_flag;
--- linux-2.2.17pre9.ext3-0.0.2e/fs/jfs/journal.c.~1~   Thu Jun 29 17:24:22 2000
+++ linux-2.2.17pre9.ext3-0.0.2e/fs/jfs/journal.c       Tue Jul  4 12:30:32 2000
@@ -131,6 +131,11 @@
                       journal->j_commit_request = transaction->t_tid;
       }

+       if (journal->j_commit_timer_active) {
+               journal->j_commit_timer_active = 0;
+               del_timer(journal->j_commit_timer);
+       }
+
       journal->j_task = NULL;
       wake_up(&journal->j_wait_done_commit);
       jfs_debug(1, "Journal thread exiting.\n");
@@ -318,7 +323,7 @@
       journal_file_buffer(bh_in, transaction, BJ_Shadow);
       journal_file_buffer(new_bh, transaction, BJ_IO);

-       return do_escape + (done_copy_out << 1);
+       return do_escape | (done_copy_out << 1);
}


@@ -784,6 +789,12 @@
       while (!err && journal->j_checkpoint_transactions != NULL)
               err = log_do_checkpoint(journal, journal->j_maxlen);
       unlock_journal(journal);
+
+       J_ASSERT(!journal->j_running_transaction);
+       J_ASSERT(!journal->j_committing_transaction);
+       J_ASSERT(!journal->j_checkpoint_transactions);
+       J_ASSERT(journal->j_head == journal->j_tail);
+       J_ASSERT(journal->j_tail_sequence == journal->j_transaction_sequence);

       return err;
}
--- linux-2.2.17pre9.ext3-0.0.2e/fs/jfs/recovery.c.~1~  Thu Jun 29 17:24:22 2000
+++ linux-2.2.17pre9.ext3-0.0.2e/fs/jfs/recovery.c      Tue Jul  4 17:29:54 2000
@@ -223,7 +223,7 @@
        */

       if (!sb->s_start) {
-               jfs_debug(1, "No recovery required, last transaction %ld\n",
+               jfs_debug(1, "No recovery required, last transaction %d\n",
                         ntohl(sb->s_sequence));
               journal->j_transaction_sequence = ++next_commit_ID;
               return 0;
@@ -327,8 +327,10 @@

                       /* If it is the commit block, then we are all done! */

-                       if (tmp->h_blocktype == htonl(JFS_COMMIT_BLOCK))
+                       if (tmp->h_blocktype == htonl(JFS_COMMIT_BLOCK)) {
+                               brelse(bh);
                               break;
+                       }

                       /* A descriptor block: we can now write all of
                        * the data blocks.  Yay, useful work is finally
@@ -376,7 +378,7 @@
                                       }

                                       mark_buffer_dirty(nbh, 1);
-                                       ll_rw_block(WRITE, 1, &nbh);
+                                       // ll_rw_block(WRITE, 1, &nbh);
                                       brelse(obh);
                                       brelse(nbh);
                               }
@@ -389,10 +391,11 @@
                                       break;

                       } /* end of tag loop */
+
+                       brelse(bh);

               } /* end of descriptor block loop */
-               brelse(bh);
-
+
               /* We have now replayed that entire transaction: start
                * looking for the next transaction. */
               next_commit_ID++;
--- linux-2.2.17pre9.ext3-0.0.2e/fs/jfs/transaction.c.~1~       Thu Jun 29 17:24:22 2000
+++ linux-2.2.17pre9.ext3-0.0.2e/fs/jfs/transaction.c   Thu Jun 29 23:29:49 2000
@@ -507,7 +507,7 @@
 * To deal with that, journal_get_undo_access requests write access to a
 * buffer for parts of non-rewindable operations such as delete
 * operations on the bitmaps.  The journaling code must keep a copy of
-` * the buffer's contents prior to the undo_access call until such time
+ * the buffer's contents prior to the undo_access call until such time
 * as we know that the buffer has definitely been committed to disk.
 *
 * We never need to know which transaction the committed data is part
--- linux-2.2.17pre9.ext3-0.0.2e/include/linux/ext3_fs.h.~1~    Thu Jun 29 17:24:22 2000
+++ linux-2.2.17pre9.ext3-0.0.2e/include/linux/ext3_fs.h        Tue Jul  4 16:43:28 2000
@@ -36,8 +36,8 @@
/*
 * The second extended file system version
 */
-#define EXT3FS_DATE            "2000/3/22"
-#define EXT3FS_VERSION         "0.0.2d"
+#define EXT3FS_DATE            "2000/07/04"
+#define EXT3FS_VERSION         "0.0.2e"

/*
 * Debug code
@@ -406,8 +406,10 @@
        */
       __u8    s_journal_uuid[16];     /* uuid of journal superblock */
       __u32   s_journal_inum;         /* inode number of journal file */
+       __u32   s_journal_dev;          /* device number of journal file */
+       __u32   s_last_orphan;          /* start of list of inodes to delete */

-       __u32   s_reserved[199];        /* Padding to the end of the block */
+       __u32   s_reserved[197];        /* Padding to the end of the block */
};

#ifdef __KERNEL__
@@ -419,6 +421,8 @@
#define EXT3_SB(sb)    (sb)
#endif

+#define NEXT_ORPHAN(inode) inode->u.ext3_i.i_dtime
+
/*
 * Codes for operating systems
 */
@@ -586,6 +590,7 @@
/* ialloc.c */
extern struct inode * ext3_new_inode (handle_t *, const struct inode *, int, int *);
extern void ext3_free_inode (handle_t *, struct inode *);
+extern struct inode * ext3_orphan_get (struct super_block * sb, ino_t ino);
extern unsigned long ext3_count_free_inodes (struct super_block *);
extern void ext3_check_inodes_bitmap (struct super_block *);

@@ -601,6 +606,7 @@
extern void ext3_read_inode (struct inode *);
extern void ext3_write_inode (struct inode *);
extern void ext3_put_inode (struct inode *);
+extern void ext3_orphan_del (handle_t *handle, struct inode *);
extern void ext3_delete_inode (struct inode *);
extern int  ext3_sync_inode (handle_t *, struct inode *);
extern int  ext3_notify_change(struct dentry *, struct iattr *);
@@ -616,6 +622,7 @@
extern int ext3_create (struct inode *,struct dentry *,int);
extern int ext3_mkdir (struct inode *,struct dentry *,int);
extern int ext3_rmdir (struct inode *,struct dentry *);
+extern void ext3_orphan_add(handle_t *, struct inode *);
extern int ext3_unlink (struct inode *,struct dentry *);
extern int ext3_symlink (struct inode *,struct dentry *,const char *);
extern int ext3_link (struct dentry *, struct inode *, struct dentry *);
--- linux-2.2.17pre9.ext3-0.0.2e/include/linux/ext3_fs_i.h.~1~  Thu Jun 29 17:24:22 2000
+++ linux-2.2.17pre9.ext3-0.0.2e/include/linux/ext3_fs_i.h      Wed Jul  5 14:45:43 2000
@@ -36,7 +36,13 @@
       __u32   i_prealloc_block;
       __u32   i_prealloc_count;
       __u32   i_high_size;
+       struct list_head i_orphan;      /* unlinked but open inodes */
       int     i_new_inode:1;  /* Is a freshly allocated inode */
+       /* i_disksize keeps track of what the inode size is ON DISK, not
+        * in memory.  During truncate, i_size is set to 0 by the VFS
+        * but the filesystem won't set i_disksize to 0 until the
+        * truncate is actually under way. */
+       off_t   i_disksize;
};

#endif /* _LINUX_EXT3_FS_I */
--- linux-2.2.17pre9.ext3-0.0.2e/include/linux/ext3_fs_sb.h.~1~ Thu Jun 29 17:41:18 2000
+++ linux-2.2.17pre9.ext3-0.0.2e/include/linux/ext3_fs_sb.h     Tue Jul  4 17:01:54 2000
@@ -65,6 +65,7 @@
       /* Journaling */
       struct inode * s_journal_inode;
       struct journal_s * s_journal;
+       struct list_head s_orphan;
};

#endif /* _LINUX_EXT3_FS_SB */
--- linux-2.2.17pre9.ext3-0.0.2e/include/linux/ext3_jfs.h.~1~   Fri Jun 30 19:53:35 2000
+++ linux-2.2.17pre9.ext3-0.0.2e/include/linux/ext3_jfs.h       Wed Jul  5 14:55:34 2000
@@ -113,4 +113,26 @@
       return err;
}

+
+/*
+ * Wrappers for journal_start/end.
+ *
+ * The only special thing we need to do here is to make sure that all
+ * journal_end calls result in the superblock being marked dirty, so
+ * that sync() will call the filesystem's write_super callback if
+ * appropriate.
+ */
+
+static inline handle_t *ext3_journal_start (struct inode *inode, int nblocks)
+{
+       return journal_start(EXT3_JOURNAL(inode), nblocks);
+}
+
+static inline int ext3_journal_stop (handle_t *handle, struct inode *inode)
+{
+       int rc = journal_stop(handle);
+       inode->i_sb->s_dirt = 1;
+       return rc;
+}
+
#endif /* _LINUX_EXT3_JFS_H */
--- linux-2.2.17pre9.ext3-0.0.2e/include/linux/fs.h.~1~ Thu Jun 29 17:41:20 2000
+++ linux-2.2.17pre9.ext3-0.0.2e/include/linux/fs.h     Wed Jul  5 14:54:03 2000
@@ -618,9 +618,6 @@
       short int               s_ibasket_max;
       struct list_head        s_dirty;        /* dirty inodes */

-       /* Pointer to journaling control structure for this filesystem */
-       journal_t             * s_journal;
-
       /* Filesystem-specific data: */
       union {
               struct minix_sb_info    minix_sb;