--- drivers/acorn/block/fd1772.c~	Thu Jan  7 16:46:58 1999
+++ drivers/acorn/block/fd1772.c	Wed May  5 23:46:42 1999
@@ -1569,7 +1569,7 @@
 	if (!filp || (filp->f_mode & (2 | OPEN_WRITE_BIT)))
 		/* if the file is mounted OR (writable now AND writable at open
 		   time) Linus: Does this cover all cases? */
-		block_fsync(inode, filp);
+		block_fsync(inode, filp, 0);
 
 	if (fd_ref[drive] < 0)
 		fd_ref[drive] = 0;
--- drivers/block/ataflop.c~	Tue Dec 29 19:23:59 1998
+++ drivers/block/ataflop.c	Wed May  5 23:46:13 1999
@@ -1986,7 +1986,7 @@
 	 * sync is required.  Otherwise, sync if filp is writable.
 	 */
 	if (filp && (filp->f_mode & (2 | OPEN_WRITE_BIT)))
-		block_fsync (filp, filp->f_dentry);
+		block_fsync (filp, filp->f_dentry, 0);
 
 	if (fd_ref[drive] < 0)
 		fd_ref[drive] = 0;
--- drivers/block/floppy.c~	Tue Apr 20 22:33:21 1999
+++ drivers/block/floppy.c	Wed May  5 23:45:40 1999
@@ -3677,7 +3677,7 @@
 	 * sync is required.  Otherwise, sync if filp is writable.
 	 */
 	if (filp && (filp->f_mode & (2 | OPEN_WRITE_BIT)))
-		block_fsync(filp, filp->f_dentry);
+		block_fsync(filp, filp->f_dentry, 0);
 
 	if (UDRS->fd_ref < 0)
 		UDRS->fd_ref=0;
--- drivers/block/swim3.c~	Tue Apr 20 22:33:02 1999
+++ drivers/block/swim3.c	Wed May  5 23:46:26 1999
@@ -941,7 +941,7 @@
 	 * sync is required.  Otherwise, sync if filp is writable.
 	 */
 	if (filp && (filp->f_mode & (2 | OPEN_WRITE_BIT)))
-		block_fsync (filp, filp->f_dentry);
+		block_fsync (filp, filp->f_dentry, 0);
 
 	fs = &floppy_states[devnum];
 	sw = fs->swim3;
--- fs/block_dev.c~	Fri Nov 13 18:07:26 1998
+++ fs/block_dev.c	Wed May  5 23:16:42 1999
@@ -292,7 +292,7 @@
  *	since the vma has no handle.
  */
  
-int block_fsync(struct file *filp, struct dentry *dentry)
+int block_fsync(struct file *filp, struct dentry *dentry, int datasync)
 {
 	return fsync_dev(dentry->d_inode->i_rdev);
 }
--- fs/buffer.c~	Thu May  6 00:54:43 1999
+++ fs/buffer.c	Thu May  6 11:14:26 1999
@@ -627,13 +627,14 @@
 	while (!list_empty(&inode->i_dirty_buffers)) {
 		bh = BH_ENTRY(inode->i_dirty_buffers.next);
 		list_del(&bh->b_inode_buffers);
-		if (!buffer_dirty(bh))
+		if (!buffer_dirty(bh) && !buffer_locked(bh))
 			bh->b_inode = NULL;
 		else {
 			bh->b_inode = &tmp;
 			list_add(&bh->b_inode_buffers, &tmp.i_dirty_buffers);
 			bh->b_count++;
-			ll_rw_block(WRITE, 1, &bh);
+			if (buffer_dirty(bh))
+				ll_rw_block(WRITE, 1, &bh);
 		}
 	}
 
--- fs/coda/dir.c~	Tue Apr 20 22:33:35 1999
+++ fs/coda/dir.c	Wed May  5 23:32:39 1999
@@ -50,7 +50,7 @@
 /* support routines */
 static int coda_venus_readdir(struct file *filp, void *dirent, 
 			      filldir_t filldir);
-int coda_fsync(struct file *, struct dentry *dentry);
+int coda_fsync(struct file *, struct dentry *dentry, int);
 
 int coda_crossvol_rename = 0;
 int coda_hasmknod = 0;
--- fs/coda/file.c~	Mon Aug 31 23:46:10 1998
+++ fs/coda/file.c	Wed May  5 23:49:58 1999
@@ -32,7 +32,7 @@
 static int coda_file_mmap(struct file * file, struct vm_area_struct * vma);
 
 /* also exported from this file (used for dirs) */
-int coda_fsync(struct file *, struct dentry *dentry);
+int coda_fsync(struct file *, struct dentry *dentry, int);
 
 struct inode_operations coda_file_inode_operations = {
 	&coda_file_operations,	/* default file operations */
@@ -205,7 +205,7 @@
         return result;
 }
 
-int coda_fsync(struct file *coda_file, struct dentry *coda_dentry)
+int coda_fsync(struct file *coda_file, struct dentry *coda_dentry, int datasync)
 {
         struct coda_inode_info *cnp;
 	struct inode *coda_inode = coda_dentry->d_inode;
@@ -234,7 +234,7 @@
 
 	down(&cont_inode->i_sem);
 
-        result = file_fsync(&cont_file ,&cont_dentry);
+        result = file_fsync(&cont_file ,&cont_dentry, 0);
 	if ( result == 0 ) {
 		result = venus_fsync(coda_inode->i_sb, &(cnp->c_fid));
 	}
--- fs/ext2/file.c~	Mon Dec 21 23:22:54 1998
+++ fs/ext2/file.c	Wed May  5 23:55:53 1999
@@ -270,7 +270,10 @@
 		buf += c;
 		count -= c;
 		mark_buffer_uptodate(bh, 1);
-		mark_buffer_dirty(bh, 0);
+		/* Even if the file is open for O_SYNC write, we need to
+		 * attach the dirty buffer to the inode to avoid a
+		 * concurrent fsync() returning early. */
+		mark_buffer_dirty_inode(bh, 0, inode);
 
 		if (filp->f_flags & O_SYNC)
 			bufferlist[buffercount++] = bh;
@@ -307,7 +310,9 @@
 		inode->u.ext2_i.i_osync--;
 	inode->i_ctime = inode->i_mtime = CURRENT_TIME;
 	*ppos = pos;
-	mark_inode_dirty(inode);
+	mark_inode_dirty_sync(inode);
+	if (filp->f_flags & O_SYNC)
+		ext2_sync_file(filp, filp->f_dentry, 0);
 	return written;
 }
 
--- fs/ext2/fsync.c~	Wed May 20 21:09:12 1998
+++ fs/ext2/fsync.c	Wed May  5 23:57:14 1999
@@ -32,254 +32,23 @@
 #include <linux/locks.h>
 
 
-#define blocksize (EXT2_BLOCK_SIZE(inode->i_sb))
-#define addr_per_block (EXT2_ADDR_PER_BLOCK(inode->i_sb))
-
-static int sync_block (struct inode * inode, u32 * block, int wait)
-{
-	struct buffer_head * bh;
-	
-	if (!*block)
-		return 0;
-	bh = get_hash_table (inode->i_dev, *block, blocksize);
-	if (!bh)
-		return 0;
-	if (wait && buffer_req(bh) && !buffer_uptodate(bh)) {
-		brelse (bh);
-		return -1;
-	}
-	if (wait || !buffer_uptodate(bh) || !buffer_dirty(bh)) {
-		brelse (bh);
-		return 0;
-	}
-	ll_rw_block (WRITE, 1, &bh);
-	bh->b_count--;
-	return 0;
-}
-
-#ifndef __LITTLE_ENDIAN
-static int sync_block_swab32 (struct inode * inode, u32 * block, int wait)
-{
-	struct buffer_head * bh;
-	
-	if (!le32_to_cpu(*block))
-		return 0;
-	bh = get_hash_table (inode->i_dev, le32_to_cpu(*block), blocksize);
-	if (!bh)
-		return 0;
-	if (wait && buffer_req(bh) && !buffer_uptodate(bh)) {
-		brelse (bh);
-		return -1;
-	}
-	if (wait || !buffer_uptodate(bh) || !buffer_dirty(bh)) {
-		brelse (bh);
-		return 0;
-	}
-	ll_rw_block (WRITE, 1, &bh);
-	bh->b_count--;
-	return 0;
-}
-#else
-#define sync_block_swab32 sync_block
-#endif
-
-
-static int sync_iblock (struct inode * inode, u32 * iblock, 
-			struct buffer_head ** bh, int wait) 
-{
-	int rc, tmp;
-	
-	*bh = NULL;
-	tmp = *iblock;
-	if (!tmp)
-		return 0;
-	rc = sync_block (inode, iblock, wait);
-	if (rc)
-		return rc;
-	*bh = bread (inode->i_dev, tmp, blocksize);
-	if (!*bh)
-		return -1;
-	return 0;
-}
-
-#ifndef __LITTLE_ENDIAN
-static int sync_iblock_swab32 (struct inode * inode, u32 * iblock, 
-			       struct buffer_head ** bh, int wait) 
-{
-	int rc, tmp;
-	
-	*bh = NULL;
-	tmp = le32_to_cpu(*iblock);
-	if (!tmp)
-		return 0;
-	rc = sync_block_swab32 (inode, iblock, wait);
-	if (rc)
-		return rc;
-	*bh = bread (inode->i_dev, tmp, blocksize);
-	if (!*bh)
-		return -1;
-	return 0;
-}
-#else
-#define sync_iblock_swab32 sync_iblock
-#endif
-
-static int sync_direct (struct inode * inode, int wait)
-{
-	int i;
-	int rc, err = 0;
-
-	for (i = 0; i < EXT2_NDIR_BLOCKS; i++) {
-		rc = sync_block (inode, inode->u.ext2_i.i_data + i, wait);
-		if (rc)
-			err = rc;
-	}
-	return err;
-}
-
-static int sync_indirect (struct inode * inode, u32 * iblock, int wait)
-{
-	int i;
-	struct buffer_head * ind_bh;
-	int rc, err = 0;
-
-	rc = sync_iblock (inode, iblock, &ind_bh, wait);
-	if (rc || !ind_bh)
-		return rc;
-	
-	for (i = 0; i < addr_per_block; i++) {
-		rc = sync_block_swab32 (inode, 
-					((u32 *) ind_bh->b_data) + i,
-					wait);
-		if (rc)
-			err = rc;
-	}
-	brelse (ind_bh);
-	return err;
-}
-
-#ifndef __LITTLE_ENDIAN
-static __inline__ int sync_indirect_swab32 (struct inode * inode, u32 * iblock, int wait)
-{
-	int i;
-	struct buffer_head * ind_bh;
-	int rc, err = 0;
-
-	rc = sync_iblock_swab32 (inode, iblock, &ind_bh, wait);
-	if (rc || !ind_bh)
-		return rc;
-	
-	for (i = 0; i < addr_per_block; i++) {
-		rc = sync_block_swab32 (inode, 
-					((u32 *) ind_bh->b_data) + i,
-					wait);
-		if (rc)
-			err = rc;
-	}
-	brelse (ind_bh);
-	return err;
-}
-#else
-#define sync_indirect_swab32 sync_indirect
-#endif
-
-static int sync_dindirect (struct inode * inode, u32 * diblock, int wait)
-{
-	int i;
-	struct buffer_head * dind_bh;
-	int rc, err = 0;
-
-	rc = sync_iblock (inode, diblock, &dind_bh, wait);
-	if (rc || !dind_bh)
-		return rc;
-	
-	for (i = 0; i < addr_per_block; i++) {
-		rc = sync_indirect_swab32 (inode,
-					   ((u32 *) dind_bh->b_data) + i,
-					   wait);
-		if (rc)
-			err = rc;
-	}
-	brelse (dind_bh);
-	return err;
-}
-
-#ifndef __LITTLE_ENDIAN
-static __inline__ int sync_dindirect_swab32 (struct inode * inode, u32 * diblock, int wait)
-{
-	int i;
-	struct buffer_head * dind_bh;
-	int rc, err = 0;
-
-	rc = sync_iblock_swab32 (inode, diblock, &dind_bh, wait);
-	if (rc || !dind_bh)
-		return rc;
-	
-	for (i = 0; i < addr_per_block; i++) {
-		rc = sync_indirect_swab32 (inode,
-					   ((u32 *) dind_bh->b_data) + i,
-					   wait);
-		if (rc)
-			err = rc;
-	}
-	brelse (dind_bh);
-	return err;
-}
-#else
-#define sync_dindirect_swab32 sync_dindirect
-#endif
-
-static int sync_tindirect (struct inode * inode, u32 * tiblock, int wait)
-{
-	int i;
-	struct buffer_head * tind_bh;
-	int rc, err = 0;
-
-	rc = sync_iblock (inode, tiblock, &tind_bh, wait);
-	if (rc || !tind_bh)
-		return rc;
-	
-	for (i = 0; i < addr_per_block; i++) {
-		rc = sync_dindirect_swab32 (inode,
-					    ((u32 *) tind_bh->b_data) + i,
-					    wait);
-		if (rc)
-			err = rc;
-	}
-	brelse (tind_bh);
-	return err;
-}
 
 /*
  *	File may be NULL when we are called. Perhaps we shouldn't
  *	even pass file to fsync ?
  */
 
-int ext2_sync_file(struct file * file, struct dentry *dentry)
+int ext2_sync_file(struct file * file, struct dentry *dentry, int datasync)
 {
-	int wait, err = 0;
+	int err;
 	struct inode *inode = dentry->d_inode;
-
-	if (S_ISLNK(inode->i_mode) && !(inode->i_blocks))
-		/*
-		 * Don't sync fast links!
-		 */
-		goto skip;
-
-	for (wait=0; wait<=1; wait++)
-	{
-		err |= sync_direct (inode, wait);
-		err |= sync_indirect (inode,
-				      inode->u.ext2_i.i_data+EXT2_IND_BLOCK,
-				      wait);
-		err |= sync_dindirect (inode,
-				       inode->u.ext2_i.i_data+EXT2_DIND_BLOCK, 
-				       wait);
-		err |= sync_tindirect (inode, 
-				       inode->u.ext2_i.i_data+EXT2_TIND_BLOCK, 
-				       wait);
-	}
-skip:
-	err |= ext2_sync_inode (inode);
+	
+	err  = fsync_inode_buffers(inode);
+	if (!(inode->i_state & I_DIRTY))
+		return err;
+	if (datasync && !(inode->i_state & I_DIRTY_DATASYNC))
+		return err;
+	
+	err |= ext2_sync_inode(inode);
 	return err ? -EIO : 0;
 }
--- fs/ext2/inode.c~	Tue Apr 20 22:33:09 1999
+++ fs/ext2/inode.c	Wed May  5 22:22:53 1999
@@ -123,7 +123,7 @@
 		}
 		memset(bh->b_data, 0, inode->i_sb->s_blocksize);
 		mark_buffer_uptodate(bh, 1);
-		mark_buffer_dirty(bh, 1);
+		mark_buffer_dirty_inode(bh, 1, inode);
 		brelse (bh);
 	} else {
 		ext2_discard_prealloc (inode);
@@ -340,7 +340,7 @@
 		goto repeat;
 	}
 	*p = le32_to_cpu(tmp);
-	mark_buffer_dirty(bh, 1);
+	mark_buffer_dirty_inode(bh, 1, inode);
 	if (IS_SYNC(inode) || inode->u.ext2_i.i_osync) {
 		ll_rw_block (WRITE, 1, &bh);
 		wait_on_buffer (bh);
--- fs/ext2/namei.c~	Tue Apr 20 22:33:36 1999
+++ fs/ext2/namei.c	Wed May  5 22:22:52 1999
@@ -304,7 +304,7 @@
 			dir->u.ext2_i.i_flags &= ~EXT2_BTREE_FL;
 			mark_inode_dirty(dir);
 			dir->i_version = ++event;
-			mark_buffer_dirty(bh, 1);
+			mark_buffer_dirty_inode(bh, 1, dir);
 			*res_dir = de;
 			*err = 0;
 			return bh;
@@ -386,7 +386,7 @@
 				      EXT2_FEATURE_INCOMPAT_FILETYPE))
 		de->file_type = EXT2_FT_REG_FILE;
 	dir->i_version = ++event;
-	mark_buffer_dirty(bh, 1);
+	mark_buffer_dirty_inode(bh, 1, dir);
 	if (IS_SYNC(dir)) {
 		ll_rw_block (WRITE, 1, &bh);
 		wait_on_buffer (bh);
@@ -439,7 +439,7 @@
 	if (S_ISBLK(mode) || S_ISCHR(mode))
 		inode->i_rdev = to_kdev_t(rdev);
 	mark_inode_dirty(inode);
-	mark_buffer_dirty(bh, 1);
+	mark_buffer_dirty_inode(bh, 1, dir);
 	if (IS_SYNC(dir)) {
 		ll_rw_block (WRITE, 1, &bh);
 		wait_on_buffer (bh);
@@ -500,7 +500,7 @@
 				      EXT2_FEATURE_INCOMPAT_FILETYPE))
 		de->file_type = EXT2_FT_DIR;
 	inode->i_nlink = 2;
-	mark_buffer_dirty(dir_block, 1);
+	mark_buffer_dirty_inode(dir_block, 1, dir);
 	brelse (dir_block);
 	inode->i_mode = S_IFDIR | (mode & (S_IRWXUGO|S_ISVTX) & ~current->fs->umask);
 	if (dir->i_mode & S_ISGID)
@@ -514,7 +514,7 @@
 				      EXT2_FEATURE_INCOMPAT_FILETYPE))
 		de->file_type = EXT2_FT_DIR;
 	dir->i_version = ++event;
-	mark_buffer_dirty(bh, 1);
+	mark_buffer_dirty_inode(bh, 1, dir);
 	if (IS_SYNC(dir)) {
 		ll_rw_block (WRITE, 1, &bh);
 		wait_on_buffer (bh);
@@ -624,7 +624,7 @@
 	dir->i_version = ++event;
 	if (retval)
 		goto end_rmdir;
-	mark_buffer_dirty(bh, 1);
+	mark_buffer_dirty_inode(bh, 1, dir);
 	if (IS_SYNC(dir)) {
 		ll_rw_block (WRITE, 1, &bh);
 		wait_on_buffer (bh);
@@ -677,7 +677,7 @@
 	if (retval)
 		goto end_unlink;
 	dir->i_version = ++event;
-	mark_buffer_dirty(bh, 1);
+	mark_buffer_dirty_inode(bh, 1, dir);
 	if (IS_SYNC(dir)) {
 		ll_rw_block (WRITE, 1, &bh);
 		wait_on_buffer (bh);
@@ -736,7 +736,7 @@
 		link[i++] = c;
 	link[i] = 0;
 	if (name_block) {
-		mark_buffer_dirty(name_block, 1);
+		mark_buffer_dirty_inode(name_block, 1, inode);
 		brelse (name_block);
 	}
 	inode->i_size = i;
@@ -750,7 +750,7 @@
 				      EXT2_FEATURE_INCOMPAT_FILETYPE))
 		de->file_type = EXT2_FT_SYMLINK;
 	dir->i_version = ++event;
-	mark_buffer_dirty(bh, 1);
+	mark_buffer_dirty_inode(bh, 1, dir);
 	if (IS_SYNC(dir)) {
 		ll_rw_block (WRITE, 1, &bh);
 		wait_on_buffer (bh);
@@ -803,7 +803,7 @@
 			de->file_type = EXT2_FT_FIFO;
 	}
 	dir->i_version = ++event;
-	mark_buffer_dirty(bh, 1);
+	mark_buffer_dirty_inode(bh, 1, dir);
 	if (IS_SYNC(dir)) {
 		ll_rw_block (WRITE, 1, &bh);
 		wait_on_buffer (bh);
@@ -904,7 +904,7 @@
 	mark_inode_dirty(old_dir);
 	if (dir_bh) {
 		PARENT_INO(dir_bh->b_data) = le32_to_cpu(new_dir->i_ino);
-		mark_buffer_dirty(dir_bh, 1);
+		mark_buffer_dirty_inode(dir_bh, 1, old_inode);
 		old_dir->i_nlink--;
 		mark_inode_dirty(old_dir);
 		if (new_inode) {
@@ -916,12 +916,12 @@
 			mark_inode_dirty(new_dir);
 		}
 	}
-	mark_buffer_dirty(old_bh,  1);
+	mark_buffer_dirty_inode(old_bh,  1, old_dir);
 	if (IS_SYNC(old_dir)) {
 		ll_rw_block (WRITE, 1, &old_bh);
 		wait_on_buffer (old_bh);
 	}
-	mark_buffer_dirty(new_bh, 1);
+	mark_buffer_dirty_inode(new_bh, 1, new_dir);
 	if (IS_SYNC(new_dir)) {
 		ll_rw_block (WRITE, 1, &new_bh);
 		wait_on_buffer (new_bh);
--- fs/ext2/truncate.c~	Mon Oct  5 18:04:34 1998
+++ fs/ext2/truncate.c	Wed May  5 22:22:45 1999
@@ -143,7 +143,7 @@
 		 */
 		bforget(bh);
 		if (ind_bh)
-			mark_buffer_dirty(ind_bh, 1);
+			mark_buffer_dirty_inode(ind_bh, 1, inode);
 		ext2_free_blocks (inode, tmp, 1);
 		goto out;
 	}
@@ -230,7 +230,7 @@
 			inode->i_ino, tmp);
 		*p = 0;
 		if (dind_bh)
-			mark_buffer_dirty(dind_bh, 1);
+			mark_buffer_dirty_inode(dind_bh, 1, inode);
 		else
 			mark_inode_dirty(inode);
 		return 0;
@@ -266,7 +266,7 @@
 		inode->i_blocks -= blocks;
 		mark_inode_dirty(inode);
 		bforget(bh);
-		mark_buffer_dirty(ind_bh, 1);
+		mark_buffer_dirty_inode(ind_bh, 1, inode);
 
 		/* accumulate blocks to free if they're contiguous */
 		if (free_count == 0)
@@ -312,7 +312,7 @@
 			inode->i_ino, tmp);
 		*p = 0;
 		if (tind_bh)
-			mark_buffer_dirty(tind_bh, 1);
+			mark_buffer_dirty_inode(tind_bh, 1, inode);
 		else
 			mark_inode_dirty(inode);
 		return 0;
@@ -425,7 +425,7 @@
 		if (bh) {
 			memset (bh->b_data + offset, 0,
 				inode->i_sb->s_blocksize - offset);
-			mark_buffer_dirty (bh, 0);
+			mark_buffer_dirty_inode (bh, 0, inode);
 			brelse (bh);
 		}
 	}
--- fs/inode.c~	Tue Apr 20 22:33:36 1999
+++ fs/inode.c	Thu May  6 01:07:34 1999
@@ -79,14 +79,14 @@
  * In short, make sure you hash any inodes _before_
  * you start marking them dirty..
  */
-void __mark_inode_dirty(struct inode *inode)
+void __mark_inode_dirty(struct inode *inode, int flags)
 {
 	struct super_block * sb = inode->i_sb;
 
 	if (sb) {
 		spin_lock(&inode_lock);
-		if (!(inode->i_state & I_DIRTY)) {
-			inode->i_state |= I_DIRTY;
+		if ((inode->i_state & flags) != flags) {
+			inode->i_state |= flags;
 			/* Only add valid (ie hashed) inodes to the dirty list */
 			if (!list_empty(&inode->i_hash)) {
 				list_del(&inode->i_list);
@@ -129,6 +129,7 @@
 	init_waitqueue(&inode->i_wait);
 	INIT_LIST_HEAD(&inode->i_hash);
 	INIT_LIST_HEAD(&inode->i_dentry);
+	INIT_LIST_HEAD(&inode->i_dirty_buffers);
 	sema_init(&inode->i_sem, 1);
 	sema_init(&inode->i_atomic_write, 1);
 }
@@ -149,7 +150,8 @@
 		list_del(&inode->i_list);
 		list_add(&inode->i_list, &inode_in_use);
 		/* Set I_LOCK, reset I_DIRTY */
-		inode->i_state ^= I_DIRTY | I_LOCK;
+		inode->i_state |= I_LOCK;
+		inode->i_state &= ~I_DIRTY;
 		spin_unlock(&inode_lock);
 
 		write_inode(inode);
@@ -194,6 +196,7 @@
 	spin_unlock(&inode_lock);
 }
 
+
 /*
  * Called with the spinlock already held..
  */
@@ -291,7 +294,7 @@
 		inode = list_entry(tmp, struct inode, i_list);
 		if (inode->i_sb != sb)
 			continue;
-		if (!inode->i_count) {
+		if (!inode->i_count && list_empty(&inode->i_dirty_buffers)) {
 			list_del(&inode->i_hash);
 			INIT_LIST_HEAD(&inode->i_hash);
 			list_del(&inode->i_list);
@@ -336,7 +339,8 @@
  *      dispose_list.
  */
 #define CAN_UNUSE(inode) \
-	(((inode)->i_count | (inode)->i_state) == 0)
+	(((inode)->i_count | (inode)->i_state) == 0 && \
+	 list_empty(&(inode)->i_dirty_buffers))
 #define INODE(entry)	(list_entry(entry, struct inode, i_list))
 
 static int free_inodes(void)
@@ -802,5 +806,5 @@
     if ( IS_NODIRATIME (inode) && S_ISDIR (inode->i_mode) ) return;
     if ( IS_RDONLY (inode) ) return;
     inode->i_atime = CURRENT_TIME;
-    mark_inode_dirty (inode);
+    mark_inode_dirty_sync (inode);
 }   /*  End Function update_atime  */
--- fs/minix/fsync.c~	Thu Nov 12 19:44:09 1998
+++ fs/minix/fsync.c	Wed May  5 23:24:36 1999
@@ -332,7 +332,7 @@
  *	NULL
  */
  
-int minix_sync_file(struct file * file, struct dentry *dentry)
+int minix_sync_file(struct file * file, struct dentry *dentry, int datasync)
 {
 	struct inode *inode = dentry->d_inode;
 	
--- fs/ncpfs/file.c~	Mon Aug 24 21:02:44 1998
+++ fs/ncpfs/file.c	Wed May  5 23:30:08 1999
@@ -26,7 +26,7 @@
 	return a < b ? a : b;
 }
 
-static int ncp_fsync(struct file *file, struct dentry *dentry)
+static int ncp_fsync(struct file *file, struct dentry *dentry, int datasync)
 {
 	return 0;
 }
--- fs/nfs/file.c~	Tue Apr 20 22:33:09 1999
+++ fs/nfs/file.c	Wed May  5 23:27:13 1999
@@ -36,7 +36,7 @@
 static ssize_t nfs_file_read(struct file *, char *, size_t, loff_t *);
 static ssize_t nfs_file_write(struct file *, const char *, size_t, loff_t *);
 static int  nfs_file_flush(struct file *);
-static int  nfs_fsync(struct file *, struct dentry *dentry);
+static int  nfs_fsync(struct file *, struct dentry *dentry, int);
 
 static struct file_operations nfs_file_operations = {
 	NULL,			/* lseek - default */
@@ -141,7 +141,7 @@
  * whether any write errors occurred for this process.
  */
 static int
-nfs_fsync(struct file *file, struct dentry *dentry)
+nfs_fsync(struct file *file, struct dentry *dentry, int datasync)
 {
 	struct inode *inode = dentry->d_inode;
 	int status;
--- fs/nfsd/vfs.c~	Tue Apr 20 22:33:36 1999
+++ fs/nfsd/vfs.c	Wed May  5 23:49:38 1999
@@ -398,7 +398,7 @@
 void
 nfsd_sync(struct inode *inode, struct file *filp)
 {
-	filp->f_op->fsync(filp, filp->f_dentry);
+	filp->f_op->fsync(filp, filp->f_dentry, 0);
 }
 
 /*
--- fs/qnx4/fsync.c~	Tue Sep  1 18:43:13 1998
+++ fs/qnx4/fsync.c	Wed May  5 23:30:54 1999
@@ -146,7 +146,7 @@
 	return err;
 }
 
-int qnx4_sync_file(struct file *file, struct dentry *dentry)
+int qnx4_sync_file(struct file *file, struct dentry *dentry, int datasync)
 {
         struct inode *inode = dentry->d_inode;
 	int wait, err = 0;
--- fs/smbfs/file.c~	Wed Mar 17 16:12:22 1999
+++ fs/smbfs/file.c	Wed May  5 23:29:22 1999
@@ -39,7 +39,7 @@
 }
 
 static int
-smb_fsync(struct file *file, struct dentry * dentry)
+smb_fsync(struct file *file, struct dentry * dentry, int datasync)
 {
 #ifdef SMBFS_DEBUG_VERBOSE
 printk("smb_fsync: sync file %s/%s\n", 
--- fs/sysv/fsync.c~	Sun Sep 13 20:12:34 1998
+++ fs/sysv/fsync.c	Wed May  5 23:28:41 1999
@@ -178,7 +178,7 @@
 	return err;
 }
 
-int sysv_sync_file(struct file * file, struct dentry *dentry)
+int sysv_sync_file(struct file * file, struct dentry *dentry, int datasync)
 {
 	int wait, err = 0;
 	struct inode *inode = dentry->d_inode;
--- include/linux/ext2_fs.h~	Mon Dec 28 06:18:28 1998
+++ include/linux/ext2_fs.h	Wed May  5 23:27:47 1999
@@ -544,7 +544,7 @@
 extern int ext2_write (struct inode *, struct file *, char *, int);
 
 /* fsync.c */
-extern int ext2_sync_file (struct file *, struct dentry *);
+extern int ext2_sync_file (struct file *, struct dentry *, int);
 
 /* ialloc.c */
 extern struct inode * ext2_new_inode (const struct inode *, int, int *);
--- include/linux/fs.h~	Wed May  5 23:43:38 1999
+++ include/linux/fs.h	Wed May  5 23:45:33 1999
@@ -402,10 +402,10 @@
 };
 
 /* Inode state bits.. */
-#define I_DIRTY_SYNC		1
-#define I_LOCK			2
-#define I_FREEING		4
-#define I_DIRTY_DATASYNC	8
+#define I_DIRTY_SYNC		1 /* Not dirty enough for O_DATASYNC */
+#define I_DIRTY_DATASYNC	2 /* Data-related inode changes pending */
+#define I_LOCK			4
+#define I_FREEING		8
 
 #define I_DIRTY (I_DIRTY_SYNC | I_DIRTY_DATASYNC)
 
--- include/linux/minix_fs.h~	Sun Nov 22 17:34:01 1998
+++ include/linux/minix_fs.h	Wed May  5 23:24:45 1999
@@ -115,7 +115,7 @@
 extern void minix_truncate(struct inode *);
 extern int init_minix_fs(void);
 extern int minix_sync_inode(struct inode *);
-extern int minix_sync_file(struct file *, struct dentry *);
+extern int minix_sync_file(struct file *, struct dentry *, int);
 
 extern struct inode_operations minix_file_inode_operations;
 extern struct inode_operations minix_dir_inode_operations;
--- include/linux/qnx4_fs.h~	Mon Aug 31 21:01:35 1998
+++ include/linux/qnx4_fs.h	Wed May  5 23:31:14 1999
@@ -114,7 +114,7 @@
 extern void qnx4_free_inode(struct inode *inode);
 extern int qnx4_unlink(struct inode *dir, struct dentry *dentry);
 extern int qnx4_rmdir(struct inode *dir, struct dentry *dentry);
-extern int qnx4_sync_file(struct file *file, struct dentry *dentry);
+extern int qnx4_sync_file(struct file *file, struct dentry *dentry, int);
 extern int qnx4_sync_inode(struct inode *inode);
 extern int qnx4_bmap(struct inode *inode, int block);
 
--- include/linux/sysv_fs.h~	Wed May  5 22:58:41 1999
+++ include/linux/sysv_fs.h	Wed May  5 23:59:15 1999
@@ -400,7 +400,7 @@
 extern void sysv_write_inode(struct inode *);
 extern int sysv_statfs(struct super_block *, struct statfs *, int);
 extern int sysv_sync_inode(struct inode *);
-extern int sysv_sync_file(struct file *, struct dentry *);
+extern int sysv_sync_file(struct file *, struct dentry *, int);
 extern int sysv_mmap(struct file *, struct vm_area_struct *);
 
 extern struct inode_operations sysv_file_inode_operations;
--- mm/filemap.c~	Tue Apr 20 22:33:14 1999
+++ mm/filemap.c	Wed May  5 23:52:28 1999
@@ -1356,7 +1356,10 @@
 				struct dentry * dentry = file->f_dentry;
 				struct inode * inode = dentry->d_inode;
 				down(&inode->i_sem);
-				error = file_fsync(file, dentry);
+				/* According to SingleUnix, we are only
+				 * required to implement fdatasync, not
+				 * fsync, consistency here. */
+				error = file_fsync(file, dentry, 1);
 				up(&inode->i_sem);
 			}
 		}
