--- /dev/null
+--- 2.4.20-pre2/fs/ext3/inode.c~ext3-o_direct Thu Aug 15 01:11:02 2002
++++ 2.4.20-pre2-akpm/fs/ext3/inode.c Thu Aug 15 01:25:55 2002
+@@ -27,6 +27,7 @@
+ #include <linux/ext3_jbd.h>
+ #include <linux/jbd.h>
+ #include <linux/locks.h>
++#include <linux/iobuf.h>
+ #include <linux/smp_lock.h>
+ #include <linux/highuid.h>
+ #include <linux/quotaops.h>
+@@ -716,9 +717,9 @@ err_out:
+ * The BKL may not be held on entry here. Be sure to take it early.
+ */
+
+-static int ext3_get_block_handle(handle_t *handle, struct inode *inode,
+- long iblock,
+- struct buffer_head *bh_result, int create)
++static int
++ext3_get_block_handle(handle_t *handle, struct inode *inode, long iblock,
++ struct buffer_head *bh_result, int create, int extend_disksize)
+ {
+ int err = -EIO;
+ int offsets[4];
+@@ -798,16 +799,18 @@ out:
+ if (err)
+ goto cleanup;
+
+- new_size = inode->i_size;
+- /*
+- * This is not racy against ext3_truncate's modification of i_disksize
+- * because VM/VFS ensures that the file cannot be extended while
+- * truncate is in progress. It is racy between multiple parallel
+- * instances of get_block, but we have the BKL.
+- */
+- if (new_size > inode->u.ext3_i.i_disksize)
+- inode->u.ext3_i.i_disksize = new_size;
+-
++ if (extend_disksize) {
++ /*
++ * This is not racy against ext3_truncate's modification of
++ * i_disksize because VM/VFS ensures that the file cannot be
++ * extended while truncate is in progress. It is racy between
++ * multiple parallel instances of get_block, but we have BKL.
++ */
++ struct ext3_inode_info *ei = EXT3_I(inode);
++ new_size = inode->i_size;
++ if (new_size > ei->i_disksize)
++ ei->i_disksize = new_size;
++ }
+ bh_result->b_state |= (1UL << BH_New);
+ goto got_it;
+
+@@ -834,7 +837,38 @@ static int ext3_get_block(struct inode *
+ handle = ext3_journal_current_handle();
+ J_ASSERT(handle != 0);
+ }
+- ret = ext3_get_block_handle(handle, inode, iblock, bh_result, create);
++ ret = ext3_get_block_handle(handle, inode, iblock,
++ bh_result, create, 1);
++ return ret;
++}
++
++#define DIO_CREDITS (EXT3_RESERVE_TRANS_BLOCKS + 32)
++
++static int
++ext3_direct_io_get_block(struct inode *inode, long iblock,
++ struct buffer_head *bh_result, int create)
++{
++ handle_t *handle = journal_current_handle();
++ int ret = 0;
++
++ lock_kernel();
++ if (handle && handle->h_buffer_credits <= EXT3_RESERVE_TRANS_BLOCKS) {
++ /*
++ * Getting low on buffer credits...
++ */
++ if (!ext3_journal_extend(handle, DIO_CREDITS)) {
++ /*
++ * Couldn't extend the transaction. Start a new one
++ */
++ ret = ext3_journal_restart(handle, DIO_CREDITS);
++ }
++ }
++ if (ret == 0)
++ ret = ext3_get_block_handle(handle, inode, iblock,
++ bh_result, create, 0);
++ if (ret == 0)
++ bh_result->b_size = (1 << inode->i_blkbits);
++ unlock_kernel();
+ return ret;
+ }
+
+@@ -852,7 +886,7 @@ struct buffer_head *ext3_getblk(handle_t
+ dummy.b_state = 0;
+ dummy.b_blocknr = -1000;
+ buffer_trace_init(&dummy.b_history);
+- *errp = ext3_get_block_handle(handle, inode, block, &dummy, create);
++ *errp = ext3_get_block_handle(handle, inode, block, &dummy, create, 1);
+ if (!*errp && buffer_mapped(&dummy)) {
+ struct buffer_head *bh;
+ bh = sb_getblk(inode->i_sb, dummy.b_blocknr);
+@@ -1349,6 +1383,67 @@ static int ext3_releasepage(struct page
+ return journal_try_to_free_buffers(journal, page, wait);
+ }
+
++static int
++ext3_direct_IO(int rw, struct inode *inode, struct kiobuf *iobuf,
++ unsigned long blocknr, int blocksize)
++{
++ struct ext3_inode_info *ei = EXT3_I(inode);
++ handle_t *handle = NULL;
++ int ret;
++ int orphan = 0;
++ loff_t offset = blocknr << inode->i_blkbits; /* ugh */
++ ssize_t count = iobuf->length; /* ditto */
++
++ if (rw == WRITE) {
++ loff_t final_size = offset + count;
++
++ lock_kernel();
++ handle = ext3_journal_start(inode, DIO_CREDITS);
++ unlock_kernel();
++ if (IS_ERR(handle)) {
++ ret = PTR_ERR(handle);
++ goto out;
++ }
++ if (final_size > inode->i_size) {
++ lock_kernel();
++ ret = ext3_orphan_add(handle, inode);
++ unlock_kernel();
++ if (ret)
++ goto out_stop;
++ orphan = 1;
++ ei->i_disksize = inode->i_size;
++ }
++ }
++
++ ret = generic_direct_IO(rw, inode, iobuf, blocknr,
++ blocksize, ext3_direct_io_get_block);
++
++out_stop:
++ if (handle) {
++ int err;
++
++ lock_kernel();
++ if (orphan)
++ ext3_orphan_del(handle, inode);
++ if (orphan && ret > 0) {
++ loff_t end = offset + ret;
++ if (end > inode->i_size) {
++ ei->i_disksize = end;
++ inode->i_size = end;
++ err = ext3_mark_inode_dirty(handle, inode);
++ if (!ret)
++ ret = err;
++ }
++ }
++ err = ext3_journal_stop(handle, inode);
++ if (ret == 0)
++ ret = err;
++ unlock_kernel();
++ }
++out:
++ return ret;
++
++}
+
+ struct address_space_operations ext3_aops = {
+ readpage: ext3_readpage, /* BKL not held. Don't need */
+@@ -1359,6 +1454,7 @@ struct address_space_operations ext3_aop
+ bmap: ext3_bmap, /* BKL held */
+ flushpage: ext3_flushpage, /* BKL not held. Don't need */
+ releasepage: ext3_releasepage, /* BKL not held. Don't need */
++ direct_IO: ext3_direct_IO, /* BKL not held. Don't need */
+ };
+
+ /*
+++ /dev/null
- fs/inode.c | 2 +-
- include/linux/fs.h | 2 +-
- kernel/ksyms.c | 1 +
- 3 files changed, 3 insertions(+), 2 deletions(-)
-
---- linux-2.4.20/fs/inode.c~inode_unhash 2003-07-13 15:23:43.000000000 -0600
-+++ linux-2.4.20-braam/fs/inode.c 2003-07-16 14:45:10.000000000 -0600
-@@ -191,7 +191,7 @@ static inline void write_inode(struct in
- inode->i_sb->s_op->write_inode(inode, sync);
- }
-
--static inline void __iget(struct inode * inode)
-+void __iget(struct inode * inode)
- {
- if (atomic_read(&inode->i_count)) {
- atomic_inc(&inode->i_count);
---- linux-2.4.20/include/linux/fs.h~inode_unhash 2003-07-13 15:23:43.000000000 -0600
-+++ linux-2.4.20-braam/include/linux/fs.h 2003-07-16 14:48:20.000000000 -0600
-@@ -1382,7 +1382,7 @@ static inline struct inode *iget(struct
- {
- return iget4(sb, ino, NULL, NULL);
- }
--
-+extern void __iget(struct inode * inode);
- extern void clear_inode(struct inode *);
- extern struct inode * get_empty_inode(void);
-
---- linux-2.4.20/kernel/ksyms.c~inode_unhash 2003-07-13 15:23:43.000000000 -0600
-+++ linux-2.4.20-braam/kernel/ksyms.c 2003-07-16 14:48:59.000000000 -0600
-@@ -141,6 +141,7 @@ EXPORT_SYMBOL(fput);
- EXPORT_SYMBOL(fget);
- EXPORT_SYMBOL(igrab);
- EXPORT_SYMBOL(iunique);
-+EXPORT_SYMBOL(__iget);
- EXPORT_SYMBOL(iget4);
- EXPORT_SYMBOL(iput);
- EXPORT_SYMBOL(force_delete);
-
-_
+++ /dev/null
- fs/inode.c | 17 +++++++++++++++++
- include/linux/fs.h | 1 +
- 2 files changed, 18 insertions(+)
-
---- linux-2.5.73/fs/inode.c~inode_unhash_2.5.75 2003-06-22 12:33:34.000000000 -0600
-+++ linux-2.5.73-braam/fs/inode.c 2003-07-15 02:15:24.000000000 -0600
-@@ -272,6 +272,18 @@ static void dispose_list(struct list_hea
- spin_unlock(&inode_lock);
- }
-
-+/** unhash_notify - notify the FS that an inode is being unhashed
-+ * @inode: inode being unhashed
-+ *
-+ * the unhash_inode method must not block
-+ */
-+static void unhash_notify(struct inode *inode)
-+{
-+ if (inode->i_sb && inode->i_sb->s_op &&
-+ inode->i_sb->s_op->unhash_inode)
-+ inode->i_sb->s_op->unhash_inode(inode);
-+}
-+
- /*
- * Invalidate all inodes for a device.
- */
-@@ -293,6 +305,7 @@ static int invalidate_list(struct list_h
- continue;
- invalidate_inode_buffers(inode);
- if (!atomic_read(&inode->i_count)) {
-+ unhash_notify(inode);
- hlist_del_init(&inode->i_hash);
- list_del(&inode->i_list);
- list_add(&inode->i_list, dispose);
-@@ -429,6 +442,7 @@ static void prune_icache(int nr_to_scan)
- if (!can_unuse(inode))
- continue;
- }
-+ unhash_notify(inode);
- hlist_del_init(&inode->i_hash);
- list_move(&inode->i_list, &freeable);
- inode->i_state |= I_FREEING;
-@@ -938,6 +952,7 @@ void __insert_inode_hash(struct inode *i
- void remove_inode_hash(struct inode *inode)
- {
- spin_lock(&inode_lock);
-+ unhash_notify(inode);
- hlist_del_init(&inode->i_hash);
- spin_unlock(&inode_lock);
- }
-@@ -977,6 +992,7 @@ void generic_delete_inode(struct inode *
- } else
- clear_inode(inode);
- spin_lock(&inode_lock);
-+ unhash_notify(inode);
- hlist_del_init(&inode->i_hash);
- spin_unlock(&inode_lock);
- wake_up_inode(inode);
-@@ -1002,6 +1018,7 @@ static void generic_forget_inode(struct
- write_inode_now(inode, 1);
- spin_lock(&inode_lock);
- inodes_stat.nr_unused--;
-+ unhash_notify(inode);
- hlist_del_init(&inode->i_hash);
- }
- list_del_init(&inode->i_list);
---- linux-2.5.73/include/linux/fs.h~inode_unhash_2.5.75 2003-07-01 11:13:41.000000000 -0600
-+++ linux-2.5.73-braam/include/linux/fs.h 2003-07-15 02:11:47.000000000 -0600
-@@ -799,6 +799,7 @@ struct super_operations {
- int (*statfs) (struct super_block *, struct kstatfs *);
- int (*remount_fs) (struct super_block *, int *, char *);
- void (*clear_inode) (struct inode *);
-+ void (*unhash_inode) (struct inode *);
- void (*umount_begin) (struct super_block *);
-
- int (*show_options)(struct seq_file *, struct vfsmount *);
-
-_