
This is reiser4 update for 2.6.12-rc2-mm3

 fs/reiser4/plugin/compress/compress.h     |    2 
 fs/reiser4/plugin/plugin.h                |    1 
 fs/reiser4/status_flags.c                 |    1 
 fs/reiser4/txnmgr.c                       |    2 
 fs/reiser4/vfs_ops.c                      |    2 

diff -puN fs/reiser4/plugin/compress/compress.c~reiser4-crc-update-1.900 fs/reiser4/plugin/compress/compress.c


 fs/reiser4/as_ops.c                       |    6 --
 fs/reiser4/cluster.h                      |   16 ++---
 fs/reiser4/flush.c                        |   14 +---
 fs/reiser4/plugin/compress/compress.c     |    5 +
 fs/reiser4/plugin/compress/compress.h     |    2 
 fs/reiser4/plugin/compress/minilzo.c      |   10 ---
 fs/reiser4/plugin/cryptcompress.c         |   89 ++++++++++++++++++------------
 fs/reiser4/plugin/cryptcompress.h         |   13 +++-
 fs/reiser4/plugin/file/file.c             |   75 ++++++++++++-------------
 fs/reiser4/plugin/file/file.h             |    4 +
 fs/reiser4/plugin/file/tail_conversion.c  |   13 ++++
 fs/reiser4/plugin/item/ctail.c            |   32 +++++-----
 fs/reiser4/plugin/item/extent_file_ops.c  |   40 +++++++++----
 fs/reiser4/plugin/item/extent_flush_ops.c |   14 ++++
 fs/reiser4/plugin/item/tail.c             |   26 ++++++--
 fs/reiser4/plugin/plugin.h                |    1 
 fs/reiser4/plugin/space/bitmap.c          |    8 +-
 fs/reiser4/status_flags.c                 |    1 
 fs/reiser4/super.h                        |    4 +
 fs/reiser4/tree_walk.c                    |    4 -
 fs/reiser4/txnmgr.c                       |    8 +-
 fs/reiser4/vfs_ops.c                      |    8 +-
 22 files changed, 239 insertions(+), 154 deletions(-)

diff -puN fs/reiser4/cluster.h~reiser4-update-2 fs/reiser4/cluster.h
--- linux-2.6.12-rc2-mm3/fs/reiser4/cluster.h~reiser4-update-2	2005-04-29 15:12:56.000000000 +0400
+++ linux-2.6.12-rc2-mm3-root/fs/reiser4/cluster.h	2005-04-29 15:12:56.000000000 +0400
@@ -26,34 +26,34 @@ static inline int inode_cluster_shift (s
 }
 
 static inline unsigned
-page_cluster_shift(struct inode * inode)
+cluster_nrpages_shift(struct inode * inode)
 {
-	return inode_cluster_shift(inode) + PAGE_CACHE_SHIFT;
+	return inode_cluster_shift(inode) - PAGE_CACHE_SHIFT;
 }
 
 /* cluster size in page units */
 static inline unsigned cluster_nrpages (struct inode * inode)
 {
-	return (1U << inode_cluster_shift(inode));
+	return 1U << cluster_nrpages_shift(inode);
 }
 
 static inline size_t inode_cluster_size (struct inode * inode)
 {
 	assert("edward-96", inode != NULL);
 
-	return (PAGE_CACHE_SIZE << inode_cluster_shift(inode));
+	return 1U << inode_cluster_shift(inode);
 }
 
 static inline unsigned long
 pg_to_clust(unsigned long idx, struct inode * inode)
 {
-	return idx >> inode_cluster_shift(inode);
+	return idx >> cluster_nrpages_shift(inode);
 }
 
 static inline unsigned long
 clust_to_pg(unsigned long idx, struct inode * inode)
 {
-	return idx << inode_cluster_shift(inode);
+	return idx << cluster_nrpages_shift(inode);
 }
 
 static inline unsigned long
@@ -103,14 +103,14 @@ count_to_nrpages(loff_t count)
 static inline unsigned long
 count_to_nrclust(loff_t count, struct inode * inode)
 {
-	return count_to_nr(count, page_cluster_shift(inode));
+	return count_to_nr(count, inode_cluster_shift(inode));
 }
 
 /* number of clusters occupied by @count pages */
 static inline cloff_t
 pgcount_to_nrclust(pgoff_t count, struct inode * inode)
 {
-	return count_to_nr(count, inode_cluster_shift(inode));
+	return count_to_nr(count, cluster_nrpages_shift(inode));
 }
 
 static inline loff_t
diff -puN fs/reiser4/flush.c~reiser4-update-2 fs/reiser4/flush.c
--- linux-2.6.12-rc2-mm3/fs/reiser4/flush.c~reiser4-update-2	2005-04-29 15:12:56.000000000 +0400
+++ linux-2.6.12-rc2-mm3-root/fs/reiser4/flush.c	2005-04-29 15:12:56.000000000 +0400
@@ -440,9 +440,6 @@ assert("nikita-3435",							\
 ON_DEBUG(atomic_t flush_cnt;)
 
 
-/* FIXME: remove me */#define FLUSH_CHECKS_CONGESTION 1
-
-#if defined (FLUSH_CHECKS_CONGESTION)
 /* check fs backing device for write congestion */
 static int check_write_congestion (void)
 {
@@ -453,10 +450,9 @@ static int check_write_congestion (void)
 	bdi = get_super_fake(sb)->i_mapping->backing_dev_info;
 	return  bdi_write_congested(bdi);
 }
-#endif /* FLUSH_CHECKS_CONGESTION */
 
 /* conditionally write flush queue */
-static int write_prepped_nodes (flush_pos_t * pos, int check_congestion)
+static int write_prepped_nodes (flush_pos_t * pos)
 {
 	int ret;
 
@@ -466,10 +462,8 @@ static int write_prepped_nodes (flush_po
 	if (!(pos->flags & JNODE_FLUSH_WRITE_BLOCKS))
 		return 0;
 
-#if defined (FLUSH_CHECKS_CONGESTION)
-	if (check_congestion && check_write_congestion())
+	if (check_write_congestion())
 		return 0;
-#endif /* FLUSH_CHECKS_CONGESTION */
 
 	ret = write_fq(pos->fq, pos->nr_written,
 		       WRITEOUT_SINGLE_STREAM | WRITEOUT_FOR_PAGE_RECLAIM);
@@ -889,7 +883,7 @@ static int rapid_flush (flush_pos_t * po
 	if (!wbq_available())
 		return 0;
 
-	return write_prepped_nodes(pos, 1);
+	return write_prepped_nodes(pos);
 }
 
 #else
@@ -1483,7 +1477,7 @@ out:
 		int ret1;
 
 		/* NOTE: seems like io is done under long term locks. */
-		ret1 = write_prepped_nodes(pos, 1);
+		ret1 = write_prepped_nodes(pos);
 		if (ret1 < 0)
 			return ret1;
 	}
diff -puN fs/reiser4/plugin/compress/compress.c~reiser4-update-2 fs/reiser4/plugin/compress/compress.c
--- linux-2.6.12-rc2-mm3/fs/reiser4/plugin/compress/compress.c~reiser4-update-2	2005-04-29 15:12:56.000000000 +0400
+++ linux-2.6.12-rc2-mm3-root/fs/reiser4/plugin/compress/compress.c	2005-04-29 15:12:56.000000000 +0400
@@ -372,6 +372,7 @@ compression_plugin compression_plugins[L
 				 .alloc = NULL,
 				 .free = NULL,
 				 .min_tfm_size = NULL,
+				 .checksum = NULL,
 				 .compress = NULL,
 				 .decompress = NULL}
 	,
@@ -391,6 +392,7 @@ compression_plugin compression_plugins[L
 				 .alloc = lzo1_alloc,
 				 .free = lzo1_free,
 				 .min_tfm_size = lzo1_min_tfm_size,
+				 .checksum = reiser4_adler32,
 				 .compress = lzo1_compress,
 				 .decompress = lzo1_decompress}
 	,
@@ -410,6 +412,7 @@ compression_plugin compression_plugins[L
 				 .alloc = NULL,
 				 .free = NULL,
 				 .min_tfm_size = NULL,
+				 .checksum = reiser4_adler32,
 				 .compress = NULL,
 				 .decompress = lzo1_decompress}
 	,
@@ -429,6 +432,7 @@ compression_plugin compression_plugins[L
 				  .alloc = gzip1_alloc,
 				  .free = gzip1_free,
 				  .min_tfm_size = gzip1_min_tfm_size,
+				  .checksum = NULL,
 				  .compress = gzip1_compress,
 				  .decompress = gzip1_decompress}
 	,
@@ -448,6 +452,7 @@ compression_plugin compression_plugins[L
 				  .alloc = gzip1_nocompress_alloc,
 				  .free = gzip1_nocompress_free,
 				  .min_tfm_size = NULL,
+				  .checksum = NULL,
 				  .compress = NULL,
 				  .decompress = gzip1_decompress}
 };
diff -puN fs/reiser4/plugin/compress/compress.h~reiser4-update-2 fs/reiser4/plugin/compress/compress.h
--- linux-2.6.12-rc2-mm3/fs/reiser4/plugin/compress/compress.h~reiser4-update-2	2005-04-29 15:12:56.000000000 +0400
+++ linux-2.6.12-rc2-mm3-root/fs/reiser4/plugin/compress/compress.h	2005-04-29 15:12:56.000000000 +0400
@@ -23,6 +23,8 @@ typedef enum {
 typedef void * coa_t;
 typedef coa_t coa_set[LAST_COMPRESSION_ID];
 
+__u32 reiser4_adler32(char * data, __u32 len);
+
 #endif /* __FS_REISER4_COMPRESS_H__ */
 
 /* Make Linus happy.
diff -puN fs/reiser4/plugin/compress/minilzo.c~reiser4-update-2 fs/reiser4/plugin/compress/minilzo.c
--- linux-2.6.12-rc2-mm3/fs/reiser4/plugin/compress/minilzo.c~reiser4-update-2	2005-04-29 15:12:56.000000000 +0400
+++ linux-2.6.12-rc2-mm3-root/fs/reiser4/plugin/compress/minilzo.c	2005-04-29 15:12:56.000000000 +0400
@@ -1110,16 +1110,6 @@ _lzo_config_check(void)
 
     COMPILE_TIME_ASSERT(lzo_sizeof_dict_t == sizeof(lzo_dict_t));
 
-#if defined(__LZO_IN_MINLZO)
-    if (r == 1)
-    {
-	lzo_uint32 adler;
-	adler = lzo_adler32(0, NULL, 0);
-	adler = lzo_adler32(adler, lzo_copyright(), 200);
-	r &= __lzo_assert(adler == 0xc76f1751L);
-    }
-#endif
-
     if (r == 1)
     {
 	r &= __lzo_assert(!schedule_insns_bug());
diff -puN fs/reiser4/plugin/cryptcompress.c~reiser4-update-2 fs/reiser4/plugin/cryptcompress.c
--- linux-2.6.12-rc2-mm3/fs/reiser4/plugin/cryptcompress.c~reiser4-update-2	2005-04-29 15:12:56.000000000 +0400
+++ linux-2.6.12-rc2-mm3-root/fs/reiser4/plugin/cryptcompress.c	2005-04-29 19:10:38.000000000 +0400
@@ -98,7 +98,7 @@ crc_inode_ok(struct inode * inode)
 	reiser4_inode * info = reiser4_inode_data(inode);
 	cryptcompress_info_t * data = cryptcompress_inode_data(inode);
 
-	if ((info->cluster_shift <= MAX_CLUSTER_SHIFT) &&
+	if (cluster_shift_ok(info->cluster_shift) &&
 	    (data->tfm[CRYPTO_TFM] == NULL) &&
 	    (data->tfm[DIGEST_TFM] == NULL))
 		return 1;
@@ -338,7 +338,7 @@ inode_invert_compression(struct inode * 
 
 	assert("edward-1308", inode != NULL);
 
-	result = force_plugin(inode, 
+	result = force_plugin(inode,
 			      PSET_COMPRESSION,
 			      compression_plugin_to_plugin
 			      (dual_compression(inode_compression_plugin(inode))));
@@ -386,12 +386,12 @@ inode_set_cluster(struct inode * object,
 		   this is a necessary parameter for cryptcompress object */
 		warning("edward-418", "create_cryptcompress: default cluster size"
 			" (%u) was assigned for the object %llu\n",
-			(1U << PAGE_CACHE_SHIFT << DEFAULT_CLUSTER_SHIFT),
+			(1U << DEFAULT_CLUSTER_SHIFT),
 			(unsigned long long)get_inode_oid(object));
 		init_default_cluster(&def);
 		data = &def;
 	}
-	assert("edward-697", *data <= MAX_CLUSTER_SHIFT);
+	assert("edward-697", cluster_shift_ok(*data));
 
 	info->cluster_shift = *data;
 	info->extmask |= (1 << CLUSTER_STAT);
@@ -863,7 +863,7 @@ try_encrypt(struct inode * inode)
 static int
 save_compressed(int old_size, int new_size, struct inode * inode)
 {
-	return (new_size + DC_CHECKSUM_SIZE + max_crypto_overhead(inode) < old_size);
+	return (new_size + (int)DC_CHECKSUM_SIZE + max_crypto_overhead(inode) < old_size);
 }
 
 /* guess if the cluster was compressed */
@@ -882,11 +882,40 @@ need_decompression(reiser4_cluster_t * c
 		 fsize_to_count(clust, inode));
 }
 
-static void set_compression_magic(__u8 * magic)
+/* append checksum at the end of input transform stream
+   and increment its length */
+static void
+dc_set_checksum(compression_plugin * cplug, tfm_cluster_t * tc)
 {
-	/* FIXME-EDWARD: Use a checksum here */
-	assert("edward-279", magic != NULL);
-	memset(magic, 0, DC_CHECKSUM_SIZE);
+	__u32 checksum;
+
+	assert("edward-1309", tc != NULL);
+	assert("edward-1310", tc->len > 0);
+	assert("edward-1311", cplug->checksum != NULL);
+
+	checksum = cplug->checksum(tfm_stream_data(tc, OUTPUT_STREAM), tc->len);
+	cputod32(checksum, (d32 *)(tfm_stream_data(tc, OUTPUT_STREAM) + tc->len));
+	tc->len += (int)DC_CHECKSUM_SIZE;
+}
+
+/* returns 0 if checksums coincide, otherwise returns 1,
+   decremrnt the length of input transform stream */
+static int
+dc_check_checksum(compression_plugin * cplug, tfm_cluster_t * tc)
+{
+	assert("edward-1312", tc != NULL);
+	assert("edward-1313", tc->len > (int)DC_CHECKSUM_SIZE);
+	assert("edward-1314", cplug->checksum != NULL);
+
+	if (cplug->checksum(tfm_stream_data(tc, INPUT_STREAM),  tc->len - (int)DC_CHECKSUM_SIZE) !=
+	    d32tocpu((d32 *)(tfm_stream_data(tc, INPUT_STREAM) + tc->len - (int)DC_CHECKSUM_SIZE))) {
+		warning("edward-156", "bad disk cluster checksum %d, (should be %d)\n",
+			(int)d32tocpu((d32 *)(tfm_stream_data(tc, INPUT_STREAM) + tc->len - (int)DC_CHECKSUM_SIZE)),
+			(int)cplug->checksum(tfm_stream_data(tc, INPUT_STREAM),  tc->len - (int)DC_CHECKSUM_SIZE));
+		return 1;
+	}
+	tc->len -= (int)DC_CHECKSUM_SIZE;
+	return 0;
 }
 
 reiser4_internal int
@@ -951,9 +980,8 @@ deflate_cluster(reiser4_cluster_t * clus
 		if (save_compressed(tc->len, dst_len, inode)) {
 			/* accept */
 			tc->len = dst_len;
-			
-			set_compression_magic(tfm_stream_data(tc, OUTPUT_STREAM) + tc->len);
-			tc->len += DC_CHECKSUM_SIZE;
+			if (cplug->checksum != NULL)
+				dc_set_checksum(cplug, tc);
 			transformed = 1;
 		}
 #if defined(SMART_COMPRESSION_MODE)
@@ -1020,7 +1048,6 @@ inflate_cluster(reiser4_cluster_t * clus
 		transformed = 1;
 	}
 	if (need_decompression(clust, inode, 0)) {
-		__u8 magic[DC_CHECKSUM_SIZE];
 		unsigned dst_len = inode_cluster_size(inode);
 		compression_plugin * cplug = inode_compression_plugin(inode);
 
@@ -1033,12 +1060,12 @@ inflate_cluster(reiser4_cluster_t * clus
 		assert("edward-1305", cplug->decompress != NULL);
 		assert("edward-910", tfm_cluster_is_set(tc));
 
-		/* Check compression magic for possible IO errors.
+		/* Check compression checksum for possible IO errors.
 
 		   End-of-cluster format created before encryption:
 
 		   data
-		   compression_magic  (4)   Indicates presence of compression
+		   checksum           (4)   Indicates presence of compression
 		                            infrastructure, should be private.
 		                            Can be absent.
 		   crypto_overhead          Created by ->align() method of crypto-plugin,
@@ -1050,17 +1077,11 @@ inflate_cluster(reiser4_cluster_t * clus
 		   tail_size           (1)   size of aligning tail,
 		                             1 <= tail_size <= blksize
 		*/
-		set_compression_magic(magic);
-
-		if (memcmp(tfm_stream_data(tc, INPUT_STREAM) + (tc->len - (size_t)DC_CHECKSUM_SIZE),
-			   magic, (size_t)DC_CHECKSUM_SIZE)) {
-			printk("edward-156: wrong compression magic %d (should be %d)\n",
-			       *((int *)(tfm_stream_data(tc, INPUT_STREAM) + (tc->len - (size_t)DC_CHECKSUM_SIZE))), *((int *)magic));
-			result = -EIO;
-			return result;
+		if (cplug->checksum != NULL) {
+			result = dc_check_checksum(cplug, tc);
+			if (result)
+				return RETERR(-EIO);
 		}
-		tc->len -= (size_t)DC_CHECKSUM_SIZE;
-
 		/* decompress cluster */
 		cplug->decompress(get_coa(tc, cplug->h.id),
 				  tfm_stream_data(tc, INPUT_STREAM), tc->len,
@@ -1328,13 +1349,13 @@ try_capture_cluster(reiser4_cluster_t * 
 	assert("edward-1033", clust->pages[0] != NULL);
 
 	node = jprivate(clust->pages[0]);
-	
+
 	assert("edward-1035", node != NULL);
-	
+
 	LOCK_JNODE(node);
 	if (clust->win)
 		inode_set_new_size(clust, inode);
-	
+
 	result = try_capture(node, ZNODE_WRITE_LOCK, 0, 0);
 	if (result)
 		goto exit;
@@ -2183,8 +2204,10 @@ jnode_truncate_ok(struct inode *inode, c
 {
 	jnode * node;
 	node = jlookup(current_tree, get_inode_oid(inode), clust_to_pg(index, inode));
-	if (node)
+	if (node) {
+		warning("edward-1315", "jnode %p is untruncated\n", node);
 		jput(node);
+	}
 	return (node == NULL);
 }
 #endif
@@ -2362,7 +2385,7 @@ set_cluster_params(struct inode * inode,
 	assert("edward-197", clust != NULL);
 	assert("edward-1072", win != NULL);
 	assert("edward-198", inode != NULL);
-	assert("edward-747", reiser4_inode_data(inode)->cluster_shift <= MAX_CLUSTER_SHIFT);
+	assert("edward-747", cluster_shift_ok(reiser4_inode_data(inode)->cluster_shift));
 
 	result = alloc_cluster_pgset(clust, cluster_nrpages(inode));
 	if (result)
@@ -2418,7 +2441,7 @@ write_cryptcompress_flow(struct file * f
 	assert("edward-161", schedulable());
 	assert("edward-748", crc_inode_ok(inode));
 	assert("edward-159", current_blocksize == PAGE_CACHE_SIZE);
-	assert("edward-749", reiser4_inode_data(inode)->cluster_shift <= MAX_CLUSTER_SHIFT);
+	assert("edward-749", cluster_shift_ok(reiser4_inode_data(inode)->cluster_shift));
 	assert("edward-1274", get_current_context()->grabbed_blocks == 0);
 
 	result = check_cryptcompress(inode);
@@ -2674,7 +2697,7 @@ static void
 set_append_cluster_key(const coord_t *coord, reiser4_key *key, struct inode *inode)
 {
 	item_key_by_coord(coord, key);
-	set_key_offset(key, ((__u64)(clust_by_coord(coord, inode)) + 1) << inode_cluster_shift(inode) << PAGE_CACHE_SHIFT);
+	set_key_offset(key, clust_to_off(clust_by_coord(coord, inode) + 1, inode));
 }
 
 /* If @index > 0, find real disk cluster of the index (@index - 1),
@@ -3286,7 +3309,7 @@ capture_cryptcompress(struct inode *inod
 		return 0;
 
 	info = cryptcompress_inode_data(inode);
-	nrpages = (i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+	nrpages = count_to_nrpages(i_size_read(inode));
 
 	if (wbc->sync_mode != WB_SYNC_ALL)
 		to_capture = min_count(wbc->nr_to_write, MAX_CLUSTERS_TO_CAPTURE(inode));
diff -puN fs/reiser4/plugin/cryptcompress.h~reiser4-update-2 fs/reiser4/plugin/cryptcompress.h
--- linux-2.6.12-rc2-mm3/fs/reiser4/plugin/cryptcompress.h~reiser4-update-2	2005-04-29 15:12:56.000000000 +0400
+++ linux-2.6.12-rc2-mm3-root/fs/reiser4/plugin/cryptcompress.h	2005-04-29 15:12:56.000000000 +0400
@@ -11,13 +11,22 @@
 #include <linux/vmalloc.h>
 
 #define MIN_CLUSTER_SIZE PAGE_CACHE_SIZE
-#define MAX_CLUSTER_SHIFT 4
-#define MAX_CLUSTER_NRPAGES (1 << MAX_CLUSTER_SHIFT)
+#define MIN_CLUSTER_SHIFT PAGE_CACHE_SHIFT
+#define MAX_CLUSTER_SHIFT 16
+#define MAX_CLUSTER_NRPAGES (1U << MAX_CLUSTER_SHIFT >> PAGE_CACHE_SHIFT)
 #define DEFAULT_CLUSTER_SHIFT 0
 #define DC_CHECKSUM_SIZE 4
 #define MIN_CRYPTO_BLOCKSIZE 8
  //#define LAZY_COMPRESSION_MODE
 
+#if REISER4_DEBUG
+static inline int
+cluster_shift_ok (int shift)
+{
+	return (shift >= MIN_CLUSTER_SHIFT) && (shift <= MAX_CLUSTER_SHIFT);
+}
+#endif
+
 typedef unsigned long cloff_t;
 
 /* Set of transform id's supported by reiser4,
diff -puN fs/reiser4/plugin/file/file.c~reiser4-update-2 fs/reiser4/plugin/file/file.c
--- linux-2.6.12-rc2-mm3/fs/reiser4/plugin/file/file.c~reiser4-update-2	2005-04-29 15:12:56.000000000 +0400
+++ linux-2.6.12-rc2-mm3-root/fs/reiser4/plugin/file/file.c	2005-04-29 19:10:38.000000000 +0400
@@ -733,8 +733,10 @@ load_file_hint(struct file *file, hint_t
 		if (IS_ERR(fsdata))
 			return PTR_ERR(fsdata);
 
+		spin_lock_inode(file->f_dentry->d_inode);
 		if (seal_is_set(&fsdata->reg.hint.seal)) {
 			*hint = fsdata->reg.hint;
+			spin_unlock_inode(file->f_dentry->d_inode);
 			/* force re-validation of the coord on the first
 			 * iteration of the read/write loop. */
 			hint->ext_coord.valid = 0;
@@ -743,6 +745,7 @@ load_file_hint(struct file *file, hint_t
 			return 0;
 		}
 		memset(&fsdata->reg.hint, 0, sizeof(hint_t));
+		spin_unlock_inode(file->f_dentry->d_inode);
 	}
 	hint_init_zero(hint);
 	return 0;
@@ -762,7 +765,10 @@ save_file_hint(struct file *file, const 
 	assert("vs-965", !IS_ERR(fsdata));
 	assert("nikita-19891",
 	       coords_equal(&hint->seal.coord1, &hint->ext_coord.coord));
+
+	spin_lock_inode(file->f_dentry->d_inode);
 	fsdata->reg.hint = *hint;
+	spin_unlock_inode(file->f_dentry->d_inode);
 	return;
 }
 
@@ -1341,6 +1347,9 @@ capture_unix_file(struct inode *inode, s
 		 * this function is out of reiser4 context and may safely
 		 * sleep on semaphore.
 		 */
+		assert("", LOCK_CNT_NIL(inode_sem_w));
+		assert("", LOCK_CNT_NIL(inode_sem_r));
+#if 0
 		if (is_in_reiser4_context()) {
 			if (down_read_trylock(&uf_info->latch) == 0) {
 /* ZAM-FIXME-HANS: please explain this error handling here, grep for
@@ -1348,6 +1357,7 @@ capture_unix_file(struct inode *inode, s
  * represent busy loops that we should recode.  Also tell me whether
  * any of them fail to return EBUSY to user space, and if yes, then
  * recode them to not use the EBUSY macro.*/
+				warning("", "does this ever happen?");
 				result = RETERR(-EBUSY);
 				reiser4_exit_context(&ctx);
 				break;
@@ -1355,7 +1365,9 @@ capture_unix_file(struct inode *inode, s
 		} else
 			down_read(&uf_info->latch);
 		LOCK_CNT_INC(inode_sem_r);
-
+#endif
+		txn_restart_current();
+		get_nonexclusive_access(uf_info, 0);
 		while (to_capture > 0) {
 			pgoff_t start;
 
@@ -1390,8 +1402,11 @@ capture_unix_file(struct inode *inode, s
 			/* there may be left more pages */
 			redirty_inode(inode);
 
+		drop_nonexclusive_access(uf_info);
+/*
 		up_read(&uf_info->latch);
 		LOCK_CNT_DEC(inode_sem_r);
+*/
 		if (result < 0) {
 			/* error happened */
 			reiser4_exit_context(&ctx);
@@ -1502,12 +1517,13 @@ readpage_unix_file(void *vp, struct page
 	if (result != CBK_COORD_FOUND) {
 		/* this indicates file corruption */
 		done_lh(&lh);
+ 		unlock_page(page);
 		return result;
 	}
 
 	if (PageUptodate(page)) {
 		done_lh(&lh);
-		unlock_page(page);
+ 		unlock_page(page);
 		return 0;
 	}
 
@@ -1515,6 +1531,7 @@ readpage_unix_file(void *vp, struct page
 	result = zload(coord->node);
 	if (result) {
 		done_lh(&lh);
+ 		unlock_page(page);
 		return result;
 	}
 
@@ -1531,6 +1548,7 @@ readpage_unix_file(void *vp, struct page
 
 		zrelse(coord->node);
 		done_lh(&lh);
+ 		unlock_page(page);
 		return RETERR(-EIO);
 	}
 
@@ -1546,14 +1564,17 @@ readpage_unix_file(void *vp, struct page
 		set_key_offset(&key, (loff_t) (page->index + 1) << PAGE_CACHE_SHIFT);
 		/* FIXME should call set_hint() */
 		unset_hint(&hint);
-	} else
+	} else {
+ 		unlock_page(page);
 		unset_hint(&hint);
+	}
 	zrelse(coord->node);
 	done_lh(&lh);
 
 	save_file_hint(file, &hint);
 
-	assert("vs-979", ergo(result == 0, (PageLocked(page) || PageUptodate(page))));
+ 	assert("vs-979", ergo(result == 0, (PageLocked(page) || PageUptodate(page))));
+ 	assert("vs-9791", ergo(result != 0, !PageLocked(page)));
 
 	return result;
 }
@@ -1631,7 +1652,7 @@ reiser4_put_user_pages(struct page **pag
 
 /* this is called with nonexclusive access obtained, file's container can not change */
 static size_t
-read_file(hint_t *hint, file_container_t container,
+read_file(hint_t *hint,
 	  struct file *file, /* file to write to */
 	  char *buf, /* address of user-space buffer */
 	  size_t count, /* number of bytes to write */
@@ -1646,33 +1667,6 @@ read_file(hint_t *hint, file_container_t
 
 	inode = file->f_dentry->d_inode;
 
-	/* we have nonexclusive access (NA) obtained. File's container may not
-	   change until we drop NA. If possible - calculate read function
-	   beforehand */
-	switch(container) {
-	case UF_CONTAINER_EXTENTS:
-		read_f = item_plugin_by_id(EXTENT_POINTER_ID)->s.file.read;
-		break;
-
-	case UF_CONTAINER_TAILS:
-		/* this is read-ahead for tails-only files */
-		result = reiser4_file_readahead(file, *off, count);
-		if (result)
-			return result;
-
-		read_f = item_plugin_by_id(FORMATTING_ID)->s.file.read;
-		break;
-
-	case UF_CONTAINER_UNKNOWN:
-		read_f = 0;
-		break;
-
-	case UF_CONTAINER_EMPTY:
-	default:
-		warning("vs-1297", "File (ino %llu) has unexpected state: %d\n",
-			(unsigned long long)get_inode_oid(inode), container);
-		return RETERR(-EIO);
-	}
 
 	/* build flow */
 	assert("vs-1250", inode_file_plugin(inode)->flow_by_inode == flow_by_inode_unix_file);
@@ -1704,9 +1698,9 @@ read_file(hint_t *hint, file_container_t
 		if (hint->ext_coord.valid == 0)
 			validate_extended_coord(&hint->ext_coord, get_key_offset(&flow.key));
 
+		assert("vs-4", hint->ext_coord.valid == 1);
 		/* call item's read method */
-		if (!read_f)
-			read_f = item_plugin_by_coord(coord)->s.file.read;
+		read_f = item_plugin_by_coord(coord)->s.file.read;
 		result = read_f(file, &flow, hint);
 		zrelse(loaded);
 		done_lh(hint->ext_coord.lh);
@@ -1807,7 +1801,7 @@ read_unix_file(struct file *file, char *
 			to_read = inode->i_size - *off;
 
 		assert("vs-1706", to_read <= left);
-		read = read_file(&hint, uf_info->container, file, buf, to_read, off);
+		read = read_file(&hint, file, buf, to_read, off);
 
 		if (user_space)
 			reiser4_put_user_pages(pages, nr_pages);
@@ -2059,6 +2053,7 @@ mmap_unix_file(struct file *file, struct
 	inode = file->f_dentry->d_inode;
 	uf_info = unix_file_inode_data(inode);
 
+  	down(&uf_info->write);
 	get_exclusive_access(uf_info);
 
 	if (!IS_RDONLY(inode) && (vma->vm_flags & (VM_MAYWRITE | VM_SHARED))) {
@@ -2067,12 +2062,14 @@ mmap_unix_file(struct file *file, struct
 		result = finish_conversion(inode);
 		if (result) {
 			drop_exclusive_access(uf_info);
+			up(&uf_info->write);
 			return result;
 		}
 
 		result = find_file_state(uf_info);
 		if (result != 0) {
 			drop_exclusive_access(uf_info);
+			up(&uf_info->write);
 			return result;
 		}
 
@@ -2084,6 +2081,7 @@ mmap_unix_file(struct file *file, struct
 			result = check_pages_unix_file(inode);
 			if (result) {
 				drop_exclusive_access(uf_info);
+				up(&uf_info->write);
 				return result;
 			}
 		}
@@ -2097,6 +2095,7 @@ mmap_unix_file(struct file *file, struct
 	}
 
 	drop_exclusive_access(uf_info);
+	up(&uf_info->write);
 	return result;
 }
 
@@ -2299,9 +2298,9 @@ write_unix_file(struct file *file, /* fi
 				(unsigned long long)get_inode_oid(inode));
 	}
 
+	save_file_hint(file, &hint);
 	up(&uf_info->write);
  	current->backing_dev_info = 0;
-	save_file_hint(file, &hint);
 
 	return count ? count : result;
 }
@@ -2317,6 +2316,7 @@ release_unix_file(struct inode *object, 
 	uf_info = unix_file_inode_data(object);
 	result = 0;
 
+  	down(&uf_info->write);
 	get_exclusive_access(uf_info);
 	if (atomic_read(&file->f_dentry->d_count) == 1 &&
 	    uf_info->container == UF_CONTAINER_EXTENTS &&
@@ -2329,6 +2329,7 @@ release_unix_file(struct inode *object, 
 		}
 	}
 	drop_exclusive_access(uf_info);
+	up(&uf_info->write);
 	return 0;
 }
 
@@ -2578,7 +2579,7 @@ init_inode_data_unix_file(struct inode *
 	init_inode_ordering(inode, crd, create);
 }
 
-/* plugin->u.file.pre_delete 
+/* plugin->u.file.pre_delete
 
    We need this because generic_delete_inode calls truncate_inode_pages before
    filesystem's delete_inode method. As result of this, reiser4 tree may have
diff -puN fs/reiser4/plugin/file/file.h~reiser4-update-2 fs/reiser4/plugin/file/file.h
--- linux-2.6.12-rc2-mm3/fs/reiser4/plugin/file/file.h~reiser4-update-2	2005-04-29 15:12:56.000000000 +0400
+++ linux-2.6.12-rc2-mm3-root/fs/reiser4/plugin/file/file.h	2005-04-29 15:12:56.000000000 +0400
@@ -85,6 +85,10 @@ typedef struct unix_file_info {
 } unix_file_info_t;
 
 struct unix_file_info *unix_file_inode_data(const struct inode * inode);
+void get_exclusive_access(unix_file_info_t *);
+void drop_exclusive_access(unix_file_info_t *);
+void get_nonexclusive_access(unix_file_info_t *, int);
+void drop_nonexclusive_access(unix_file_info_t *);
 
 #include "../item/extent.h"
 #include "../item/tail.h"
diff -puN fs/reiser4/plugin/file/tail_conversion.c~reiser4-update-2 fs/reiser4/plugin/file/tail_conversion.c
--- linux-2.6.12-rc2-mm3/fs/reiser4/plugin/file/tail_conversion.c~reiser4-update-2	2005-04-29 15:12:56.000000000 +0400
+++ linux-2.6.12-rc2-mm3-root/fs/reiser4/plugin/file/tail_conversion.c	2005-04-29 15:12:56.000000000 +0400
@@ -32,6 +32,7 @@ get_exclusive_access(unix_file_info_t *u
 	BUG_ON(get_current_context()->trans->atom != NULL);
 	LOCK_CNT_INC(inode_sem_w);
 	down_write(&uf_info->latch);
+	uf_info->exclusive_use = 1;
 	assert("vs-1713", uf_info->ea_owner == NULL);
 	assert("vs-1713", atomic_read(&uf_info->nr_neas) == 0);
 	ON_DEBUG(uf_info->ea_owner = current);
@@ -43,6 +44,7 @@ drop_exclusive_access(unix_file_info_t *
 	assert("vs-1714", uf_info->ea_owner == current);
 	assert("vs-1715", atomic_read(&uf_info->nr_neas) == 0);
 	ON_DEBUG(uf_info->ea_owner = NULL);
+	uf_info->exclusive_use = 0;
 	up_write(&uf_info->latch);
 	assert("nikita-3049", LOCK_CNT_NIL(inode_sem_r));
 	assert("nikita-3049", LOCK_CNT_GTZ(inode_sem_w));
@@ -408,8 +410,19 @@ tail2extent(unix_file_info_t *uf_info)
 			release_all_pages(pages, sizeof_array(pages));
 			if (result)
 				goto error;
+			/* we have to drop exclusive access to avoid deadlock
+			 * which may happen because called by
+			 * reiser4_writepages capture_unix_file requires to get
+			 * non-exclusive access to a file. It is safe to drop
+			 * EA in the middle of tail2extent conversion because
+			 * write_unix_file/unix_setattr(truncate)/release_unix_file(extent2tail)
+			 * are serialized by uf_info->write semaphore and
+			 * because read_unix_file works (should at least) on
+			 * partially converted files */
+			drop_exclusive_access(uf_info);
 			/* throttle the conversion */
 			reiser4_throttle_write(inode);
+			get_exclusive_access(uf_info);
 		}
 	}
 
diff -puN fs/reiser4/plugin/item/ctail.c~reiser4-update-2 fs/reiser4/plugin/item/ctail.c
--- linux-2.6.12-rc2-mm3/fs/reiser4/plugin/item/ctail.c~reiser4-update-2	2005-04-29 15:12:56.000000000 +0400
+++ linux-2.6.12-rc2-mm3-root/fs/reiser4/plugin/item/ctail.c	2005-04-29 19:10:38.000000000 +0400
@@ -54,11 +54,10 @@ cluster_shift_by_coord(const coord_t * c
 }
 
 static unsigned long
-pg_by_coord(const coord_t * coord)
+off_by_coord(const coord_t * coord)
 {
 	reiser4_key  key;
-
-	return get_key_offset(item_key_by_coord(coord, &key)) >> PAGE_CACHE_SHIFT;
+	return get_key_offset(item_key_by_coord(coord, &key));
 }
 
 static int
@@ -88,7 +87,7 @@ clust_by_coord(const coord_t * coord, st
 		assert("edward-1237", !coord_is_unprepped_ctail(coord));
 		shift = cluster_shift_by_coord(coord);
 	}
-	return pg_by_coord(coord) >> shift;
+	return off_by_coord(coord) >> shift;
 }
 
 static int unsigned long
@@ -100,7 +99,7 @@ disk_cluster_size (const coord_t * coord
 	   is meaninless if ctail is unprepped */
 	assert("edward-1238", !coord_is_unprepped_ctail(coord));
 
-	return PAGE_CACHE_SIZE << cluster_shift_by_coord(coord);
+	return 1 << cluster_shift_by_coord(coord);
 }
 
 /* true if the key is of first disk cluster item */
@@ -235,15 +234,18 @@ init_ctail(coord_t * to /* coord of item
 	return 0;
 }
 
+/* plugin->u.item.b.lookup:
+   NULL: We are looking for item keys only */
+
+#if REISER4_DEBUG
 reiser4_internal int
 ctail_ok (const coord_t *coord)
 {
 	return coord_is_unprepped_ctail(coord) ||
-		(cluster_shift_by_coord(coord) <= MAX_CLUSTER_SHIFT);
+		cluster_shift_ok(cluster_shift_by_coord(coord));
 }
 
-/* plugin->u.item.b.lookup:
-   NULL: We are looking for item keys only */
+/* plugin->u.item.b.check */
 reiser4_internal int
 check_ctail (const coord_t * coord, const char **error)
 {
@@ -254,9 +256,7 @@ check_ctail (const coord_t * coord, cons
 	}
 	return 0;
 }
-
-/* plugin->u.item.b.check */
-
+#endif
 
 /* plugin->u.item.b.paste */
 reiser4_internal int
@@ -860,7 +860,7 @@ reiser4_internal reiser4_key *
 append_key_ctail(const coord_t *coord, reiser4_key *key)
 {
 	assert("edward-1241", item_id_by_coord(coord) == CTAIL_ID);
-	assert("edward-1242", cluster_shift_by_coord(coord) <= MAX_CLUSTER_SHIFT);
+	assert("edward-1242", cluster_shift_ok(cluster_shift_by_coord(coord)));
 
 	item_key_by_coord(coord, key);
 	set_key_offset(key, ((__u64)(clust_by_coord(coord, NULL)) + 1) << cluster_shift_by_coord(coord) << PAGE_CACHE_SHIFT);
@@ -1067,7 +1067,7 @@ do_convert_ctail(flush_pos_t * pos, crc_
 	switch (mode) {
 	case CRC_APPEND_ITEM:
 		assert("edward-1229", info->flow.length != 0);
-		assert("edward-1256", cluster_shift_by_coord(&pos->coord) <= MAX_CLUSTER_SHIFT);
+		assert("edward-1256", cluster_shift_ok(cluster_shift_by_coord(&pos->coord)));
 		result = insert_crc_flow_in_place(&pos->coord, &pos->lock, &info->flow, info->inode);
 		break;
 	case CRC_OVERWRITE_ITEM:
@@ -1360,7 +1360,9 @@ utmost_child_ctail(const coord_t * coord
 	if (!is_disk_cluster_key(&key, coord))
 		*child = NULL;
 	else
-		*child = jlookup(current_tree, get_key_objectid(item_key_by_coord(coord, &key)), pg_by_coord(coord));
+		*child = jlookup(current_tree,
+				 get_key_objectid(item_key_by_coord(coord, &key)),
+				 off_to_pg(get_key_offset(&key)));
 	return 0;
 }
 
@@ -1601,7 +1603,7 @@ convert_ctail(flush_pos_t * pos)
 			/* convert unpprepped ctail to prepped one */
 			int shift;
 			shift = inode_cluster_shift(item_convert_data(pos)->inode);
-			assert("edward-1259", shift <= MAX_CLUSTER_SHIFT);
+			assert("edward-1259", cluster_shift_ok(shift));
 			cputod8(shift, &ctail_formatted_at(&pos->coord)->cluster_shift);
 		}
 		break;
diff -puN fs/reiser4/plugin/item/extent_file_ops.c~reiser4-update-2 fs/reiser4/plugin/item/extent_file_ops.c
--- linux-2.6.12-rc2-mm3/fs/reiser4/plugin/item/extent_file_ops.c~reiser4-update-2	2005-04-29 15:12:56.000000000 +0400
+++ linux-2.6.12-rc2-mm3-root/fs/reiser4/plugin/item/extent_file_ops.c	2005-04-29 19:10:38.000000000 +0400
@@ -644,6 +644,8 @@ extent_balance_dirty_pages(struct inode 
 			   hint_t *hint)
 {
 	int result;
+	int excl;
+	unix_file_info_t *uf_info;
 
 	if (hint->ext_coord.valid)
 		set_hint(hint, &f->key, ZNODE_WRITE_LOCK);
@@ -666,7 +668,19 @@ extent_balance_dirty_pages(struct inode 
 			return result;
 	}
 
-	reiser4_throttle_write(inode);
+	if (!reiser4_is_set(inode->i_sb, REISER4_ATOMIC_WRITE)) {
+		uf_info = unix_file_inode_data(inode);
+		excl = unix_file_inode_data(inode)->exclusive_use;
+		if (excl)
+			drop_exclusive_access(uf_info);
+		else
+			drop_nonexclusive_access(uf_info);
+		reiser4_throttle_write(inode);
+		if (excl)
+			get_exclusive_access(uf_info);
+		else
+			get_nonexclusive_access(uf_info, 0);
+	}
 	return 0;
 }
 
@@ -1185,7 +1199,6 @@ extent_readpage_filler(void *data, struc
 				      TWIG_LEVEL, CBK_UNIQUE, NULL);
 		if (result != CBK_COORD_FOUND) {
 			unset_hint(hint);
-			lock_page(page);
 			return result;
 		}
 		ext_coord->valid = 0;
@@ -1194,7 +1207,12 @@ extent_readpage_filler(void *data, struc
 	if (zload(ext_coord->coord.node)) {
 		unset_hint(hint);
 		done_lh(ext_coord->lh);
-		lock_page(page);
+		return RETERR(-EIO);
+	}
+	if (!item_is_extent(&ext_coord->coord)) {
+		/* tail conversion is running in parallel */
+		unset_hint(hint);
+		done_lh(ext_coord->lh);
 		return RETERR(-EIO);
 	}
 
@@ -1208,6 +1226,8 @@ extent_readpage_filler(void *data, struc
 	if (!PageUptodate(page)) {
 		result = do_readpage_extent(ext_by_ext_coord(ext_coord),
 					    ext_coord->extension.extent.pos_in_unit, page);
+		if (result)
+			unlock_page(page);
 	} else {
 		unlock_page(page);
 		result = 0;
@@ -1262,16 +1282,14 @@ call_readpage(struct file *file, struct 
 	if (result)
 		return result;
 
+	lock_page(page);
 	if (!PageUptodate(page)) {
-		lock_page(page);
-		if (!PageUptodate(page)) {
-			unlock_page(page);
-			page_detach_jnode(page, page->mapping, page->index);
-			warning("jmacd-97178", "page is not up to date");
-			return RETERR(-EIO);
-		}
 		unlock_page(page);
+		page_detach_jnode(page, page->mapping, page->index);
+		warning("jmacd-97178", "page is not up to date");
+		return RETERR(-EIO);
 	}
+	unlock_page(page);
 	return 0;
 }
 
@@ -1349,7 +1367,7 @@ read_extent(struct file *file, flow_t *f
 		} else {
 			if (!PageUptodate(page)) {
 				lock_page(page);
-				
+
 				assert("", page->mapping == mapping);
 				if (PageUptodate(page))
 					unlock_page(page);
diff -puN fs/reiser4/plugin/item/extent_flush_ops.c~reiser4-update-2 fs/reiser4/plugin/item/extent_flush_ops.c
--- linux-2.6.12-rc2-mm3/fs/reiser4/plugin/item/extent_flush_ops.c~reiser4-update-2	2005-04-29 15:12:56.000000000 +0400
+++ linux-2.6.12-rc2-mm3-root/fs/reiser4/plugin/item/extent_flush_ops.c	2005-04-29 15:12:56.000000000 +0400
@@ -279,7 +279,9 @@ exit:
 /* ask block allocator for some blocks */
 static void
 extent_allocate_blocks(reiser4_blocknr_hint *preceder,
-		       reiser4_block_nr wanted_count, reiser4_block_nr *first_allocated, reiser4_block_nr *allocated, block_stage_t block_stage)
+		       reiser4_block_nr wanted_count,
+		       reiser4_block_nr *first_allocated, reiser4_block_nr *allocated,
+		       block_stage_t block_stage)
 {
 	*allocated = wanted_count;
 	preceder->max_dist = 0;	/* scan whole disk, if needed */
@@ -288,7 +290,7 @@ extent_allocate_blocks(reiser4_blocknr_h
 	preceder->block_stage = block_stage;
 
 	/* FIXME: we do not handle errors here now */
-	check_me("vs-420", reiser4_alloc_blocks (preceder, first_allocated, allocated, BA_PERMANENT) == 0);
+	check_me("vs-420", reiser4_alloc_blocks(preceder, first_allocated, allocated, BA_PERMANENT) == 0);
 	/* update flush_pos's preceder to last allocated block number */
 	preceder->blk = *first_allocated + *allocated - 1;
 }
@@ -795,6 +797,10 @@ alloc_extent(flush_pos_t *flush_pos)
 		else
 			block_stage = BLOCK_UNALLOCATED;
 
+		/* look at previous unit if possible. If it is allocated, make preceder more precise */
+		if (coord->unit_pos && (state_of_extent(ext - 1) == ALLOCATED_EXTENT))
+			pos_hint(flush_pos)->blk = extent_get_start(ext - 1) + extent_get_width(ext - 1);
+
 		/* allocate new block numbers for protected nodes */
 		extent_allocate_blocks(pos_hint(flush_pos), protected, &first_allocated, &allocated, block_stage);
 
@@ -934,6 +940,10 @@ squalloc_extent(znode *left, const coord
 		else
 			block_stage = BLOCK_UNALLOCATED;
 
+		/* look at previous unit if possible. If it is allocated, make preceder more precise */
+		if (coord->unit_pos && (state_of_extent(ext - 1) == ALLOCATED_EXTENT))
+			pos_hint(flush_pos)->blk = extent_get_start(ext - 1) + extent_get_width(ext - 1);
+
 		/* allocate new block numbers for protected nodes */
 		extent_allocate_blocks(pos_hint(flush_pos), protected, &first_allocated, &allocated, block_stage);
 		if (allocated != protected)
diff -puN fs/reiser4/plugin/item/tail.c~reiser4-update-2 fs/reiser4/plugin/item/tail.c
--- linux-2.6.12-rc2-mm3/fs/reiser4/plugin/item/tail.c~reiser4-update-2	2005-04-29 15:12:56.000000000 +0400
+++ linux-2.6.12-rc2-mm3-root/fs/reiser4/plugin/item/tail.c	2005-04-29 19:10:38.000000000 +0400
@@ -454,6 +454,8 @@ tail_balance_dirty_pages(struct address_
 {
 	int result;
 	struct inode *inode;
+	int excl;
+	unix_file_info_t *uf_info;
 
 	if (hint->ext_coord.valid)
 		set_hint(hint, &f->key, ZNODE_WRITE_LOCK);
@@ -475,12 +477,24 @@ tail_balance_dirty_pages(struct address_
 			return result;
 	}
 
-	/* FIXME-VS: this is temporary: the problem is that bdp takes inodes
-	   from sb's dirty list and it looks like nobody puts there inodes of
-	   files which are built of tails */
-	move_inode_out_from_sync_inodes_loop(mapping);
-
-	reiser4_throttle_write(inode);
+	if (!reiser4_is_set(inode->i_sb, REISER4_ATOMIC_WRITE)) {
+		/* FIXME-VS: this is temporary: the problem is that bdp takes
+		   inodes from sb's dirty list and it looks like nobody puts
+		   there inodes of files which are built of tails */
+		move_inode_out_from_sync_inodes_loop(mapping);
+
+		uf_info = unix_file_inode_data(inode);
+		excl = unix_file_inode_data(inode)->exclusive_use;
+		if (excl)
+			drop_exclusive_access(uf_info);
+		else
+			drop_nonexclusive_access(uf_info);
+		reiser4_throttle_write(inode);
+		if (excl)
+			get_exclusive_access(uf_info);
+		else
+			get_nonexclusive_access(uf_info, 0);
+	}
 	return 0;
 }
 
diff -puN fs/reiser4/plugin/plugin.h~reiser4-update-2 fs/reiser4/plugin/plugin.h
--- linux-2.6.12-rc2-mm3/fs/reiser4/plugin/plugin.h~reiser4-update-2	2005-04-29 15:12:56.000000000 +0400
+++ linux-2.6.12-rc2-mm3-root/fs/reiser4/plugin/plugin.h	2005-04-29 15:12:56.000000000 +0400
@@ -454,6 +454,7 @@ typedef struct compression_plugin {
 	void (*free) (coa_t coa, tfm_action act);
 	/* minimal size of the flow we still try to compress */
 	int (*min_tfm_size) (void);
+	__u32 (*checksum) (char * data, __u32 length);
 	/* main transform procedures */
 	void (*compress)   (coa_t coa, __u8 *src_first, unsigned src_len,
 			    __u8 *dst_first, unsigned *dst_len);
diff -puN fs/reiser4/plugin/space/bitmap.c~reiser4-update-2 fs/reiser4/plugin/space/bitmap.c
--- linux-2.6.12-rc2-mm3/fs/reiser4/plugin/space/bitmap.c~reiser4-update-2	2005-04-29 15:12:56.000000000 +0400
+++ linux-2.6.12-rc2-mm3-root/fs/reiser4/plugin/space/bitmap.c	2005-04-29 15:12:56.000000000 +0400
@@ -461,11 +461,11 @@ reiser4_set_bits(char *addr, bmap_off_t 
     Jean-loup Gailly        Mark Adler
     jloup@gzip.org          madler@alumni.caltech.edu
 
-    The above comment applies only to the adler32 function.
+    The above comment applies only to the reiser4_adler32 function.
 */
 
-static __u32
-adler32(char *data, __u32 len)
+reiser4_internal __u32
+reiser4_adler32(char *data, __u32 len)
 {
 	unsigned char *t = data;
 	__u32 s1 = 1;
@@ -493,7 +493,7 @@ adler32(char *data, __u32 len)
 static __u32
 bnode_calc_crc(const struct bitmap_node *bnode, unsigned long size)
 {
-	return adler32(bnode_commit_data(bnode), bmap_size(size));
+	return reiser4_adler32(bnode_commit_data(bnode), bmap_size(size));
 }
 
 
diff -puN fs/reiser4/status_flags.c~reiser4-update-2 fs/reiser4/status_flags.c
--- linux-2.6.12-rc2-mm3/fs/reiser4/status_flags.c~reiser4-update-2	2005-04-29 15:12:56.000000000 +0400
+++ linux-2.6.12-rc2-mm3-root/fs/reiser4/status_flags.c	2005-04-29 15:12:56.000000000 +0400
@@ -3,7 +3,6 @@
 
 /* Functions that deal with reiser4 status block, query status and update it, if needed */
 
-#include <linux/page-flags.h>
 #include <linux/bio.h>
 #include <linux/highmem.h>
 #include <linux/fs.h>
diff -puN fs/reiser4/super.h~reiser4-update-2 fs/reiser4/super.h
--- linux-2.6.12-rc2-mm3/fs/reiser4/super.h~reiser4-update-2	2005-04-29 15:12:56.000000000 +0400
+++ linux-2.6.12-rc2-mm3-root/fs/reiser4/super.h	2005-04-29 15:12:56.000000000 +0400
@@ -63,7 +63,9 @@ typedef enum {
 	 * directories. */
 	REISER4_NO_PSEUDO = 5,
 	/* load all bitmap blocks at mount time */
-	REISER4_DONT_LOAD_BITMAP = 6
+	REISER4_DONT_LOAD_BITMAP = 6,
+	/* enforce atomicity during write(2) */
+	REISER4_ATOMIC_WRITE = 7
 } reiser4_fs_flag;
 
 /*
diff -puN fs/reiser4/tree_walk.c~reiser4-update-2 fs/reiser4/tree_walk.c
--- linux-2.6.12-rc2-mm3/fs/reiser4/tree_walk.c~reiser4-update-2	2005-04-29 15:12:56.000000000 +0400
+++ linux-2.6.12-rc2-mm3-root/fs/reiser4/tree_walk.c	2005-04-29 15:12:56.000000000 +0400
@@ -238,7 +238,7 @@ link_left_and_right(znode * left, znode 
 
 			ON_DEBUG(left->right_version = atomic_inc_return(&delim_key_version););
 
-		} else if (ZF_ISSET(left->right, JNODE_HEARD_BANSHEE)) {
+		} else if (ZF_ISSET(left->right, JNODE_HEARD_BANSHEE) && left->right != right) {
 
 			ON_DEBUG(
 				left->right->left_version = atomic_inc_return(&delim_key_version);
@@ -271,7 +271,7 @@ link_left_and_right(znode * left, znode 
 
 			ON_DEBUG(right->left_version = atomic_inc_return(&delim_key_version););
 
-		} else if (ZF_ISSET(right->left, JNODE_HEARD_BANSHEE)) {
+		} else if (ZF_ISSET(right->left, JNODE_HEARD_BANSHEE) && right->left != left) {
 
 			ON_DEBUG(
 				right->left->right_version = atomic_inc_return(&delim_key_version);
diff -puN fs/reiser4/txnmgr.c~reiser4-update-2 fs/reiser4/txnmgr.c
--- linux-2.6.12-rc2-mm3/fs/reiser4/txnmgr.c~reiser4-update-2	2005-04-29 15:12:56.000000000 +0400
+++ linux-2.6.12-rc2-mm3-root/fs/reiser4/txnmgr.c	2005-04-29 19:10:38.000000000 +0400
@@ -1385,7 +1385,7 @@ static int txn_try_to_fuse_small_atom (t
 	int atom_stage;
 	txn_atom *atom_2;
 	int repeat;
-	
+
 	assert ("zam-1051", atom->stage < ASTAGE_PRE_COMMIT);
 
 	atom_stage = atom->stage;
@@ -1415,9 +1415,9 @@ static int txn_try_to_fuse_small_atom (t
 			UNLOCK_ATOM(atom_2);
 		}
 	}
-	spin_unlock_txnmgr(tmgr);
 	atom->flags |= ATOM_CANCEL_FUSION;
- out: 
+ out:
+	spin_unlock_txnmgr(tmgr);
 	if (repeat) {
 		UNLOCK_ATOM(atom);
 		return -E_REPEAT;
@@ -1507,7 +1507,7 @@ flush_some_atom(long *nr_submitted, cons
 	ret = flush_current_atom(flags, nr_submitted, &atom);
 	if (ret == 0) {
 		if (*nr_submitted == 0 || atom_should_commit_asap(atom)) {
-			if (atom->capture_count < tmgr->atom_min_size && 
+			if (atom->capture_count < tmgr->atom_min_size &&
 			    !(atom->flags & ATOM_CANCEL_FUSION)) {
 				ret =txn_try_to_fuse_small_atom(tmgr, atom);
 				if (ret == -E_REPEAT)
diff -puN fs/reiser4/vfs_ops.c~reiser4-update-2 fs/reiser4/vfs_ops.c
--- linux-2.6.12-rc2-mm3/fs/reiser4/vfs_ops.c~reiser4-update-2	2005-04-29 15:12:56.000000000 +0400
+++ linux-2.6.12-rc2-mm3-root/fs/reiser4/vfs_ops.c	2005-04-29 19:10:38.000000000 +0400
@@ -530,7 +530,7 @@ reiser4_destroy_inode(struct inode *inod
 	kmem_cache_free(inode_cache, container_of(info, reiser4_inode_object, p));
 }
 
-/* put_inode of super_operations 
+/* put_inode of super_operations
 
    we use put_inode to call pre_delete method of file plugin if it is defined
    and if inode is unlinked and if it is about to drop inode reference count to
@@ -542,7 +542,7 @@ reiser4_put_inode(struct inode *inode)
 	file_plugin *fplug;
 
 	fplug = inode_file_plugin(inode);
-	if (fplug == NULL || 
+	if (fplug == NULL ||
 	    inode->i_nlink != 0 ||
 	    atomic_read(&inode->i_count) > 1 ||
 	    fplug->pre_delete == NULL)
@@ -551,7 +551,7 @@ reiser4_put_inode(struct inode *inode)
 	init_context(&ctx, inode->i_sb);
 	/* kill cursors which might be attached to inode if it were a directory one */
 	kill_cursors(inode);
-	fplug->pre_delete(inode);	
+	fplug->pre_delete(inode);
 	reiser4_exit_context(&ctx);
 }
 
@@ -1022,6 +1022,8 @@ do {						\
 	/* Don't load all bitmap blocks at mount time, it is useful
 	   for machines with tiny RAM and large disks. */
 	PUSH_BIT_OPT("dont_load_bitmap", REISER4_DONT_LOAD_BITMAP);
+	/* disable transaction commits during write() */
+	PUSH_BIT_OPT("atomic_write", REISER4_ATOMIC_WRITE);
 
 	PUSH_OPT ({
 		/* tree traversal readahead parameters:
diff -puN fs/reiser4/as_ops.c~reiser4-update-2 fs/reiser4/as_ops.c
--- linux-2.6.12-rc2-mm3/fs/reiser4/as_ops.c~reiser4-update-2	2005-04-29 18:48:49.000000000 +0400
+++ linux-2.6.12-rc2-mm3-root/fs/reiser4/as_ops.c	2005-04-29 18:48:49.000000000 +0400
@@ -158,13 +158,9 @@ reiser4_readpage(struct file *f /* file 
 		result = fplug->readpage(f, page);
 	else
 		result = RETERR(-EINVAL);
-	if (result != 0) {
-		SetPageError(page);
-		unlock_page(page);
-	}
 
 	reiser4_exit_context(&ctx);
-	return 0;
+	return result;
 }
 
 static int filler(void *vp, struct page *page)

_
