
update for reiser4 in 2.6.12-rc2-mm3


 fs/reiser4/carry.c                       |    2 
 fs/reiser4/cluster.h                     |   23 ++
 fs/reiser4/context.c                     |   19 ++
 fs/reiser4/flush.c                       |   10 -
 fs/reiser4/inode.c                       |    2 
 fs/reiser4/plugin/compress/compress.c    |  187 +++++++++++++----------
 fs/reiser4/plugin/compress/compress.h    |    3 
 fs/reiser4/plugin/cryptcompress.c        |  251 +++++++++++++++++++------------
 fs/reiser4/plugin/cryptcompress.h        |    1 
 fs/reiser4/plugin/dir/dir.c              |    7 
 fs/reiser4/plugin/dir/hashed_dir.c       |    2 
 fs/reiser4/plugin/file/file.c            |   23 ++
 fs/reiser4/plugin/item/ctail.c           |    9 -
 fs/reiser4/plugin/item/extent_file_ops.c |  128 ++++++++++++---
 fs/reiser4/plugin/object.c               |  150 +-----------------
 fs/reiser4/plugin/plugin.h               |   14 -
 fs/reiser4/safe_link.c                   |   23 +-
 fs/reiser4/safe_link.h                   |    2 
 fs/reiser4/tree.c                        |    2 
 fs/reiser4/tree_walk.c                   |   27 ---
 fs/reiser4/tree_walk.h                   |    9 -
 fs/reiser4/txnmgr.c                      |   54 ++++++
 fs/reiser4/txnmgr.h                      |    6 
 fs/reiser4/vfs_ops.c                     |   51 +++---
 24 files changed, 576 insertions(+), 429 deletions(-)

diff -puN fs/reiser4/carry.c~reiser4-update fs/reiser4/carry.c
--- linux-2.6.12-rc2-mm3/fs/reiser4/carry.c~reiser4-update	2005-04-19 17:58:43.362946727 +0400
+++ linux-2.6.12-rc2-mm3-vs/fs/reiser4/carry.c	2005-04-19 17:58:43.486931444 +0400
@@ -966,7 +966,7 @@ lock_carry_node(carry_level * level /* l
 		assert("nikita-1186", reference_point != NULL);
 	}
 	if (node->parent && (result == 0)) {
-		result = reiser4_get_parent(&tmp_lh, reference_point, ZNODE_WRITE_LOCK, 0);
+		result = reiser4_get_parent(&tmp_lh, reference_point, ZNODE_WRITE_LOCK);
 		if (result != 0) {
 			;	/* nothing */
 		} else if (znode_get_level(tmp_lh.node) == 0) {
diff -puN fs/reiser4/cluster.h~reiser4-update fs/reiser4/cluster.h
--- linux-2.6.12-rc2-mm3/fs/reiser4/cluster.h~reiser4-update	2005-04-19 17:58:43.367946111 +0400
+++ linux-2.6.12-rc2-mm3-vs/fs/reiser4/cluster.h	2005-04-19 17:58:43.488931198 +0400
@@ -257,6 +257,29 @@ void tfm_cluster_set_uptodate (tfm_clust
 void tfm_cluster_clr_uptodate (tfm_cluster_t * tc);
 unsigned long clust_by_coord(const coord_t * coord, struct inode * inode);
 
+/* move cluster handle to the target position
+   specified by the page of index @pgidx
+*/
+static inline void
+move_cluster_forward(reiser4_cluster_t * clust, struct inode * inode,
+		     pgoff_t pgidx, int * progress)
+{
+	assert("edward-1297", clust != NULL);
+	assert("edward-1298", inode != NULL);
+
+	reset_cluster_params(clust);
+	if (*progress &&
+	    /* Hole in the indices. Hint became invalid and can not be
+	       used by find_cluster_item() even if seal/node versions
+	       will coincide */
+	    pg_to_clust(pgidx, inode) != clust->index + 1) {
+		unset_hint(clust->hint);
+		invalidate_hint_cluster(clust);
+	}
+	*progress = 1;
+	clust->index = pg_to_clust(pgidx, inode);
+}
+
 static inline int
 alloc_clust_pages(reiser4_cluster_t * clust, struct inode * inode )
 {
diff -puN fs/reiser4/context.c~reiser4-update fs/reiser4/context.c
--- linux-2.6.12-rc2-mm3/fs/reiser4/context.c~reiser4-update	2005-04-19 17:58:43.373945371 +0400
+++ linux-2.6.12-rc2-mm3-vs/fs/reiser4/context.c	2005-04-19 17:58:43.489931075 +0400
@@ -173,6 +173,25 @@ reiser4_internal void reiser4_exit_conte
 			txn_restart(context);
 			balance_dirty_pages_at(context);
 		}
+
+		/* if filesystem is mounted with -o sync or -o dirsync - commit
+		   transaction.  FIXME: TXNH_DONT_COMMIT is used to avoid
+		   commiting on exit_context when inode semaphore is held and
+		   to have ktxnmgrd to do commit instead to get better
+		   concurrent filesystem accesses. But, when one mounts with -o
+		   sync, he cares more about reliability than about
+		   performance. So, for now we have this simple mount -o sync
+		   support. */
+		if (context->super->s_flags & (MS_SYNCHRONOUS | MS_DIRSYNC)) {
+			txn_atom *atom;
+
+			atom = get_current_atom_locked_nocheck();
+			if (atom) {
+				atom->flags |= ATOM_FORCE_COMMIT;
+				context->trans->flags &= ~TXNH_DONT_COMMIT;
+				UNLOCK_ATOM(atom);
+			}
+		}
 		txn_end(context);
 	}
 	done_context(context);
diff -puN fs/reiser4/flush.c~reiser4-update fs/reiser4/flush.c
--- linux-2.6.12-rc2-mm3/fs/reiser4/flush.c~reiser4-update	2005-04-19 17:58:43.379944632 +0400
+++ linux-2.6.12-rc2-mm3-vs/fs/reiser4/flush.c	2005-04-19 17:58:43.492930705 +0400
@@ -1191,7 +1191,7 @@ static int alloc_pos_and_ancestors(flush
 	} else {
 		if (!znode_is_root(pos->lock.node)) {
 			/* all formatted nodes except tree root */
-			ret = reiser4_get_parent(&plock, pos->lock.node, ZNODE_WRITE_LOCK, 0);
+			ret = reiser4_get_parent(&plock, pos->lock.node, ZNODE_WRITE_LOCK);
 			if (ret)
 				goto exit;
 
@@ -1704,11 +1704,11 @@ static int squalloc_upper_levels (flush_
 	init_load_count(&left_parent_load);
 	init_load_count(&right_parent_load);
 
- 	ret = reiser4_get_parent(&left_parent_lock, left, ZNODE_WRITE_LOCK, 0);
+ 	ret = reiser4_get_parent(&left_parent_lock, left, ZNODE_WRITE_LOCK);
 	if (ret)
 		goto out;
 
-	ret = reiser4_get_parent(&right_parent_lock, right, ZNODE_WRITE_LOCK, 0);
+	ret = reiser4_get_parent(&right_parent_lock, right, ZNODE_WRITE_LOCK);
 	if (ret)
 		goto out;
 
@@ -1811,7 +1811,7 @@ static int lock_parent_and_allocate_znod
 	init_lh(&parent_lock);
 	init_load_count(&parent_load);
 
-	ret = reiser4_get_parent(&parent_lock, node, ZNODE_WRITE_LOCK, 0);
+	ret = reiser4_get_parent(&parent_lock, node, ZNODE_WRITE_LOCK);
 	if (ret)
 		goto out;
 
@@ -2224,7 +2224,7 @@ static int handle_pos_to_twig (flush_pos
 	init_lh(&parent_lock);
 	init_load_count(&parent_load);
 
-	ret = reiser4_get_parent(&parent_lock, pos->lock.node, ZNODE_WRITE_LOCK, 0);
+	ret = reiser4_get_parent(&parent_lock, pos->lock.node, ZNODE_WRITE_LOCK);
 	if (ret)
 		goto out;
 
diff -puN fs/reiser4/inode.c~reiser4-update fs/reiser4/inode.c
--- linux-2.6.12-rc2-mm3/fs/reiser4/inode.c~reiser4-update	2005-04-19 17:58:43.384944016 +0400
+++ linux-2.6.12-rc2-mm3-vs/fs/reiser4/inode.c	2005-04-19 17:58:43.494930458 +0400
@@ -473,7 +473,7 @@ reiser4_iget(struct super_block *super /
 			print_key("sought for", key);
 			print_key("found", &found_key);
 		}
-		if (inode_file_plugin(inode)->not_linked(inode)) {
+		if (inode->i_nlink == 0) {
 			warning("nikita-3559", "Unlinked inode found: %llu\n",
 				(unsigned long long)get_inode_oid(inode));
 		}
diff -puN fs/reiser4/plugin/compress/compress.c~reiser4-update fs/reiser4/plugin/compress/compress.c
--- linux-2.6.12-rc2-mm3/fs/reiser4/plugin/compress/compress.c~reiser4-update	2005-04-19 17:58:43.389943399 +0400
+++ linux-2.6.12-rc2-mm3-vs/fs/reiser4/plugin/compress/compress.c	2005-04-19 17:58:43.495930335 +0400
@@ -12,42 +12,6 @@
 #include <linux/hardirq.h>
 
 /******************************************************************************/
-/*                         null compression                                   */
-/******************************************************************************/
-
-#define NONE_NRCOPY 1
-
-static int
-null_min_tfm_size(void)
-{
-	return 1;
-}
-
-static void
-null_compress(coa_t coa, __u8 * src_first, unsigned src_len,
-	      __u8 * dst_first, unsigned *dst_len)
-{
-	int i;
-	assert("edward-793", coa == NULL);
-	assert("edward-794", src_first != NULL);
-	assert("edward-795", dst_first != NULL);
-	assert("edward-796", src_len != 0);
-	assert("edward-797", dst_len != NULL);
-
-	for (i = 0; i < NONE_NRCOPY; i++)
-		memcpy(dst_first, src_first, src_len);
-	*dst_len = src_len;
-	return;
-}
-
-static void
-null_decompress(coa_t coa, __u8 * src_first, unsigned src_len,
-		__u8 * dst_first, unsigned *dst_len)
-{
-	impossible("edward-798", "trying to decompress uncompressed data");
-}
-
-/******************************************************************************/
 /*                         gzip1 compression                                  */
 /******************************************************************************/
 
@@ -55,6 +19,16 @@ null_decompress(coa_t coa, __u8 * src_fi
 #define GZIP1_DEF_WINBITS		15
 #define GZIP1_DEF_MEMLEVEL		MAX_MEM_LEVEL
 
+static int
+gzip1_init(void)
+{
+	int ret = -ENOSYS;
+#if REISER4_GZIP_TFM
+	ret = 0;
+#endif
+	return ret;
+}
+
 static int gzip1_overrun(unsigned src_len UNUSED_ARG)
 {
 	return 0;
@@ -64,9 +38,8 @@ static coa_t
 gzip1_alloc(tfm_action act)
 {
 	coa_t coa = NULL;
-	int ret = -ENXIO;
 #if REISER4_GZIP_TFM
-	ret = 0;
+	int ret = 0;
 	switch (act) {
 	case TFM_WRITE:	/* compress */
 		coa = vmalloc(zlib_deflate_workspacesize());
@@ -74,7 +47,7 @@ gzip1_alloc(tfm_action act)
 			ret = -ENOMEM;
 			break;
 		}
-		xmemset(coa, 0, zlib_deflate_workspacesize());
+		memset(coa, 0, zlib_deflate_workspacesize());
 		break;
 	case TFM_READ:	/* decompress */
 		coa = vmalloc(zlib_inflate_workspacesize());
@@ -82,25 +55,54 @@ gzip1_alloc(tfm_action act)
 			ret = -ENOMEM;
 			break;
 		}
-		xmemset(coa, 0, zlib_inflate_workspacesize());
+		memset(coa, 0, zlib_inflate_workspacesize());
 		break;
 	default:
 		impossible("edward-767",
 			   "trying to alloc workspace for unknown tfm action");
 	}
-#endif
 	if (ret) {
 		warning("edward-768",
 			"alloc workspace for gzip1 (tfm action = %d) failed\n",
 			act);
 		return ERR_PTR(ret);
 	}
+#endif
 	return coa;
 }
 
-static void gzip1_free(coa_t coa, tfm_action act)
+static coa_t
+gzip1_nocompress_alloc(tfm_action act)
 {
+	coa_t coa = NULL;
 #if REISER4_GZIP_TFM
+	int ret = 0;
+	switch (act) {
+	case TFM_WRITE:	/* compress */
+		break;
+	case TFM_READ:	/* decompress */
+		coa = vmalloc(zlib_inflate_workspacesize());
+		if (!coa) {
+			ret = -ENOMEM;
+			break;
+		}
+		memset(coa, 0, zlib_inflate_workspacesize());
+		break;
+	default:
+		impossible("edward-1299", "unknown tfm action");
+	}
+	if (ret) {
+		warning("edward-1300",
+			"alloc workspace for gzip1 (tfm action = %d) failed\n",
+			act);
+		return ERR_PTR(ret);
+	}
+#endif
+	return coa;
+}
+
+static void gzip1_free(coa_t coa, tfm_action act)
+{
 	assert("edward-769", coa != NULL);
 
 	switch (act) {
@@ -111,10 +113,24 @@ static void gzip1_free(coa_t coa, tfm_ac
 		vfree(coa);
 		break;
 	default:
-		impossible("edward-770",
-			   "free workspace for unknown tfm action");
+		impossible("edward-770", "unknown tfm action");
+	}
+	return;
+}
+
+static void gzip1_nocompress_free(coa_t coa, tfm_action act)
+{
+	assert("edward-1301", coa != NULL);
+
+	switch (act) {
+	case TFM_READ:	/* decompress */
+		vfree(coa);
+	case TFM_WRITE:	/* compress */
+		impossible("edward-1302",
+			   "trying to free non-allocated workspace");
+	default:
+		impossible("edward-1303", "unknown tfm action");
 	}
-#endif
 	return;
 }
 
@@ -132,7 +148,7 @@ gzip1_compress(coa_t coa, __u8 * src_fir
 	int ret = 0;
 	struct z_stream_s stream;
 
-	xmemset(&stream, 0, sizeof(stream));
+	memset(&stream, 0, sizeof(stream));
 
 	assert("edward-842", coa != NULL);
 	assert("edward-875", src_len != 0);
@@ -176,7 +192,7 @@ gzip1_decompress(coa_t coa, __u8 * src_f
 	int ret = 0;
 	struct z_stream_s stream;
 
-	xmemset(&stream, 0, sizeof(stream));
+	memset(&stream, 0, sizeof(stream));
 
 	assert("edward-843", coa != NULL);
 	assert("edward-876", src_len != 0);
@@ -220,15 +236,6 @@ gzip1_decompress(coa_t coa, __u8 * src_f
 }
 
 /******************************************************************************/
-/*                            none compression                                */
-/******************************************************************************/
-
-static int none_overrun(unsigned src_len UNUSED_ARG)
-{
-	return 0;
-}
-
-/******************************************************************************/
 /*                            lzo1 compression                                */
 /******************************************************************************/
 
@@ -277,11 +284,12 @@ lzo1_free(coa_t coa, tfm_action act)
 	switch (act) {
 	case TFM_WRITE:	/* compress */
 		vfree(coa);
-	case TFM_READ:	/* decompress */
 		break;
+	case TFM_READ:	/* decompress */
+		impossible("edward-1304",
+			   "trying to free non-allocated workspace");
 	default:
-		impossible("edward-880",
-			   "trying to free workspace for unknown tfm action");
+		impossible("edward-880", "unknown tfm action");
 	}
 	return;
 }
@@ -358,31 +366,35 @@ compression_plugin compression_plugins[L
 				       "absence of any compression transform",
 				       .linkage = TYPE_SAFE_LIST_LINK_ZERO}
 				 ,
-				 .overrun = none_overrun,
+				 .dual = NONE_COMPRESSION_ID,
+				 .init = NULL,
+				 .overrun = NULL,
 				 .alloc = NULL,
 				 .free = NULL,
 				 .min_tfm_size = NULL,
 				 .compress = NULL,
 				 .decompress = NULL}
 	,
-	[NULL_COMPRESSION_ID] = {
+	[LZO1_COMPRESSION_ID] = {
 				 .h = {
 				       .type_id =
 				       REISER4_COMPRESSION_PLUGIN_TYPE,
-				       .id = NULL_COMPRESSION_ID,
+				       .id = LZO1_COMPRESSION_ID,
 				       .pops = NULL,
-				       .label = "null",
-				       .desc = "NONE_NRCOPY times of memcpy",
+				       .label = "lzo1",
+				       .desc = "lzo1 compression transform",
 				       .linkage = TYPE_SAFE_LIST_LINK_ZERO}
 				 ,
-				 .overrun = none_overrun,
-				 .alloc = NULL,
-				 .free = NULL,
-				 .min_tfm_size = null_min_tfm_size,
-				 .compress = null_compress,
-				 .decompress = null_decompress}
+				 .dual = LZO1_NO_COMPRESSION_ID,
+				 .init = NULL,
+				 .overrun = lzo1_overrun,
+				 .alloc = lzo1_alloc,
+				 .free = lzo1_free,
+				 .min_tfm_size = lzo1_min_tfm_size,
+				 .compress = lzo1_compress,
+				 .decompress = lzo1_decompress}
 	,
-	[LZO1_COMPRESSION_ID] = {
+	[LZO1_NO_COMPRESSION_ID] = {
 				 .h = {
 				       .type_id =
 				       REISER4_COMPRESSION_PLUGIN_TYPE,
@@ -392,11 +404,13 @@ compression_plugin compression_plugins[L
 				       .desc = "lzo1 compression transform",
 				       .linkage = TYPE_SAFE_LIST_LINK_ZERO}
 				 ,
-				 .overrun = lzo1_overrun,
-				 .alloc = lzo1_alloc,
-				 .free = lzo1_free,
-				 .min_tfm_size = lzo1_min_tfm_size,
-				 .compress = lzo1_compress,
+				 .dual = LZO1_COMPRESSION_ID,
+				 .init = NULL,
+				 .overrun = NULL,
+				 .alloc = NULL,
+				 .free = NULL,
+				 .min_tfm_size = NULL,
+				 .compress = NULL,
 				 .decompress = lzo1_decompress}
 	,
 	[GZIP1_COMPRESSION_ID] = {
@@ -409,12 +423,33 @@ compression_plugin compression_plugins[L
 					.desc = "gzip1 compression transform",
 					.linkage = TYPE_SAFE_LIST_LINK_ZERO}
 				  ,
+				  .dual = GZIP1_NO_COMPRESSION_ID,
+				  .init = gzip1_init,
 				  .overrun = gzip1_overrun,
 				  .alloc = gzip1_alloc,
 				  .free = gzip1_free,
 				  .min_tfm_size = gzip1_min_tfm_size,
 				  .compress = gzip1_compress,
 				  .decompress = gzip1_decompress}
+	,
+	[GZIP1_NO_COMPRESSION_ID] = {
+				  .h = {
+					.type_id =
+					REISER4_COMPRESSION_PLUGIN_TYPE,
+					.id = GZIP1_COMPRESSION_ID,
+					.pops = NULL,
+					.label = "gzip1",
+					.desc = "gzip1 compression transform",
+					.linkage = TYPE_SAFE_LIST_LINK_ZERO}
+				  ,
+				  .dual = GZIP1_COMPRESSION_ID,
+				  .init = gzip1_init,
+				  .overrun = NULL,
+				  .alloc = gzip1_nocompress_alloc,
+				  .free = gzip1_nocompress_free,
+				  .min_tfm_size = NULL,
+				  .compress = NULL,
+				  .decompress = gzip1_decompress}
 };
 
 /*
diff -puN fs/reiser4/plugin/compress/compress.h~reiser4-update fs/reiser4/plugin/compress/compress.h
--- linux-2.6.12-rc2-mm3/fs/reiser4/plugin/compress/compress.h~reiser4-update	2005-04-19 17:58:43.393942906 +0400
+++ linux-2.6.12-rc2-mm3-vs/fs/reiser4/plugin/compress/compress.h	2005-04-19 17:58:43.496930212 +0400
@@ -13,9 +13,10 @@ typedef enum {
 
 typedef enum {
 	NONE_COMPRESSION_ID,
-	NULL_COMPRESSION_ID,
 	LZO1_COMPRESSION_ID,
+	LZO1_NO_COMPRESSION_ID,
 	GZIP1_COMPRESSION_ID,
+	GZIP1_NO_COMPRESSION_ID,
 	LAST_COMPRESSION_ID,
 } reiser4_compression_id;
 
diff -puN fs/reiser4/plugin/cryptcompress.c~reiser4-update fs/reiser4/plugin/cryptcompress.c
--- linux-2.6.12-rc2-mm3/fs/reiser4/plugin/cryptcompress.c~reiser4-update	2005-04-19 17:58:43.399942167 +0400
+++ linux-2.6.12-rc2-mm3-vs/fs/reiser4/plugin/cryptcompress.c	2005-04-19 17:58:43.500929719 +0400
@@ -107,6 +107,18 @@ crc_inode_ok(struct inode * inode)
 }
 #endif
 
+static int
+check_cryptcompress(struct inode * inode)
+{
+	/* FIXME-EDWARD: Add check of cipher support here */
+	int result = 0;
+
+	assert("edward-1307", inode_compression_plugin(inode) != NULL);
+	if (inode_compression_plugin(inode)->init)
+		result = inode_compression_plugin(inode)->init();
+	return result;
+}
+
 static crypto_stat_t * inode_crypto_stat (struct inode * inode)
 {
 	assert("edward-90", inode != NULL);
@@ -311,9 +323,35 @@ inode_set_crypto(struct inode * object, 
 	return result;
 }
 
-static void
+static compression_plugin *
+dual_compression(compression_plugin * cplug)
+{
+	assert("edward-130", cplug != NULL);
+	return compression_plugin_by_id(cplug->dual);
+}
+
+/* set dual compression plugin */
+static int
+inode_invert_compression(struct inode * inode)
+{
+	int result;
+
+	assert("edward-1308", inode != NULL);
+
+	result = force_plugin(inode, 
+			      PSET_COMPRESSION,
+			      compression_plugin_to_plugin
+			      (dual_compression(inode_compression_plugin(inode))));
+	if (result)
+		return result;
+	mark_inode_dirty(inode);
+	return 0;
+}
+
+static int
 inode_set_compression(struct inode * object, compression_data_t * data)
 {
+	int result = 0;
 	compression_data_t def;
 	reiser4_inode * info = reiser4_inode_data(object);
 
@@ -321,10 +359,15 @@ inode_set_compression(struct inode * obj
 		init_default_compression(&def);
 		data = &def;
 	}
+	if (compression_plugin_by_id(data->coa)->init) {
+		result = compression_plugin_by_id(data->coa)->init();
+		if (result)
+			return result;
+	}
 	plugin_set_compression(&info->pset, compression_plugin_by_id(data->coa));
 	info->plugin_mask |= (1 << PSET_COMPRESSION);
 
-	return;
+	return 0;
 }
 
 static int
@@ -388,8 +431,9 @@ create_cryptcompress(struct inode *objec
 		goto error;
 
 	/* set compression */
-	inode_set_compression(object, data->compression);
-
+	result = inode_set_compression(object, data->compression);
+	if (result)
+		goto error;
 	/* set cluster info */
 	result = inode_set_cluster(object, data->cluster);
 	if (result)
@@ -626,7 +670,7 @@ eq_to_ldk(znode *node, const reiser4_key
 #endif
 
 /* The core search procedure.
-   If result is not cbk_errored current znode is locked */
+   If returned value is not cbk_errored, current znode is locked */
 static int
 find_cluster_item(hint_t * hint,
 		  const reiser4_key *key,   /* key of the item we are
@@ -776,7 +820,9 @@ max_crypto_overhead(struct inode * inode
 static unsigned
 compress_overhead(struct inode * inode, int in_len)
 {
-	return inode_compression_plugin(inode)->overrun(in_len);
+	return (inode_compression_plugin(inode)->overrun != NULL ?
+		inode_compression_plugin(inode)->overrun(in_len) :
+		0);
 }
 
 /* Since small input stream can not get compressed,
@@ -789,15 +835,18 @@ min_size_to_compress(struct inode * inod
 	return inode_compression_plugin(inode)->min_tfm_size();
 }
 
+#ifndef LAZY_COMPRESSION_MODE
+#define SHOULD_COMPRESS_CLUSTER(index) 1
+#else
+#define SHOULD_COMPRESS_CLUSTER(index) (!test_bit(0, &index))
+#endif
 
 /* The following two functions represent reiser4 compression policy */
 static int
-try_compress(tfm_cluster_t * tc, struct inode * inode)
+try_compress(tfm_cluster_t * tc, cloff_t index, struct inode * inode)
 {
-	assert("edward-1037", min_size_to_compress(inode) > 0 &&
-	       min_size_to_compress(inode) < inode_cluster_size(inode));
-
-	return (inode_compression_plugin(inode) != compression_plugin_by_id(NONE_COMPRESSION_ID)) &&
+	return (inode_compression_plugin(inode)->compress != NULL) &&
+		SHOULD_COMPRESS_CLUSTER(index) &&
 		(tc->len >= min_size_to_compress(inode));
 }
 
@@ -827,9 +876,10 @@ need_decompression(reiser4_cluster_t * c
 	assert("edward-142", tc != 0);
 	assert("edward-143", inode != NULL);
 
-	return (inode_compression_plugin(inode) != compression_plugin_by_id(NONE_COMPRESSION_ID)) &&
-		(tc->len < (encrypted ? inode_scaled_offset(inode, fsize_to_count(clust, inode)) : fsize_to_count(clust, inode)));
-
+	return tc->len <
+		(encrypted ?
+		 inode_scaled_offset(inode, fsize_to_count(clust, inode)) :
+		 fsize_to_count(clust, inode));
 }
 
 static void set_compression_magic(__u8 * magic)
@@ -863,8 +913,9 @@ grab_tfm_stream(struct inode * inode, tf
 	return 0;
 }
 
-/* Common deflate cluster manager */
+#define SMART_COMPRESSION_MODE
 
+/* Common deflate cluster manager */
 reiser4_internal int
 deflate_cluster(reiser4_cluster_t * clust, struct inode * inode)
 {
@@ -878,7 +929,7 @@ deflate_cluster(reiser4_cluster_t * clus
 
 	if (result)
 		return result;
-	if (try_compress(tc, inode)) {
+	if (try_compress(tc, clust->index, inode)) {
 		/* try to compress, discard bad results */
 		__u32 dst_len;
 		compression_plugin * cplug = inode_compression_plugin(inode);
@@ -900,11 +951,20 @@ 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;
 			transformed = 1;
 		}
+#if defined(SMART_COMPRESSION_MODE)
+		else {
+			/* discard */
+			inode_invert_compression(inode);
+			warning("edward-1309",
+				"incompressible data: inode %llu, cluster %lu",
+				(unsigned long long)get_inode_oid(inode), clust->index);
+		}
+#endif
 	}
 	if (try_encrypt(inode)) {
 		crypto_plugin * cplug;
@@ -970,6 +1030,7 @@ inflate_cluster(reiser4_cluster_t * clus
 		result = grab_tfm_stream(inode, tc, TFM_READ, OUTPUT_STREAM);
 		if (result)
 			return result;
+		assert("edward-1305", cplug->decompress != NULL);
 		assert("edward-910", tfm_cluster_is_set(tc));
 
 		/* Check compression magic for possible IO errors.
@@ -1033,6 +1094,9 @@ readpage_cryptcompress(void *vp, struct 
 	assert("edward-88", PageLocked(page));
 	assert("edward-89", page->mapping && page->mapping->host);
 
+	result = check_cryptcompress(page->mapping->host);
+	if (result)
+		return result;
 	file = vp;
 	if (file)
 		assert("edward-113", page->mapping == file->f_dentry->d_inode->i_mapping);
@@ -1071,6 +1135,8 @@ readpages_cryptcompress(struct file *fil
 	assert("edward-1112", mapping != NULL);
 	assert("edward-1113", mapping->host != NULL);
 
+	if (check_cryptcompress(mapping->host))
+		return;
 	fplug = inode_file_plugin(mapping->host);
 
 	assert("edward-1114", fplug == file_plugin_by_id(CRC_FILE_PLUGIN_ID));
@@ -1262,16 +1328,13 @@ try_capture_cluster(reiser4_cluster_t * 
 	assert("edward-1033", clust->pages[0] != NULL);
 
 	node = jprivate(clust->pages[0]);
-
+	
 	assert("edward-1035", node != NULL);
-
-	if (clust->win) {
-		spin_lock_inode(inode);
-		LOCK_JNODE(node);
+	
+	LOCK_JNODE(node);
+	if (clust->win)
 		inode_set_new_size(clust, inode);
-	}
-	else
-		LOCK_JNODE(node);
+	
 	result = try_capture(node, ZNODE_WRITE_LOCK, 0, 0);
 	if (result)
 		goto exit;
@@ -1279,8 +1342,6 @@ try_capture_cluster(reiser4_cluster_t * 
  exit:
 	assert("edward-1034", !result);
 	UNLOCK_JNODE(node);
-	if (clust->win)
-		spin_unlock_inode(inode);
 	jput(node);
 	return result;
 }
@@ -1361,20 +1422,6 @@ grab_cluster_pages(struct inode * inode,
 	return result;
 }
 
-UNUSED_ARG static void
-set_cluster_unlinked(reiser4_cluster_t * clust, struct inode * inode)
-{
-	jnode * node;
-
-	node = jprivate(clust->pages[0]);
-
-	assert("edward-640", node);
-
-	LOCK_JNODE(node);
-	JF_SET(node, JNODE_NEW);
-	UNLOCK_JNODE(node);
-}
-
 /* put cluster pages */
 static void
 release_cluster_pages(reiser4_cluster_t * clust, int from)
@@ -1700,7 +1747,7 @@ invalidate_hint_cluster(reiser4_cluster_
 	assert("edward-1291", clust != NULL);
 	assert("edward-1292", clust->hint != NULL);
 
-	longterm_unlock_znode(clust->hint->ext_coord.lh);
+	done_lh(clust->hint->ext_coord.lh);
 	clust->hint->ext_coord.valid = 0;
 }
 
@@ -1870,7 +1917,12 @@ find_cluster(reiser4_cluster_t * clust,
 	set_key_offset(&ra_info.key_to_stop, get_key_offset(max_key()));
 
 	while (f.length) {
-		result = find_cluster_item(hint, &f.key, (write ? ZNODE_WRITE_LOCK : ZNODE_READ_LOCK), NULL, FIND_EXACT, 0);
+		result = find_cluster_item(hint,
+					   &f.key,
+					   (write ? ZNODE_WRITE_LOCK : ZNODE_READ_LOCK),
+					   NULL,
+					   FIND_EXACT,
+					   (write ? CBK_FOR_INSERT : 0));
 		switch (result) {
 		case CBK_COORD_NOTFOUND:
 			if (inode_scaled_offset(inode, clust_to_off(cl_idx, inode)) == get_key_offset(&f.key)) {
@@ -2214,16 +2266,16 @@ truncate_page_cluster(struct inode *inod
 	return;
 }
 
-/* Prepare cluster handle before write. Called by all the clients which
-   age going to modify the page cluster and put it into a transaction
-   (file_write, truncate, writepages, etc..)
+/* Prepare cluster handle before write and(or) capture. This function
+   is called by all the clients which modify page cluster and(or) put
+   it into a transaction (file_write, truncate, writepages, etc..)
 
    . grab cluster pages;
    . reserve disk space;
    . maybe read pages from disk and set the disk cluster dirty;
    . maybe write hole;
-   . maybe create 'unprepped' disk cluster (if the disk cluster is fake (isn't represenred
-     by any items on disk)
+   . maybe create 'unprepped' disk cluster if the last one is fake
+     (isn't represenred by any items on disk)
 */
 
 static int
@@ -2321,10 +2373,6 @@ set_cluster_params(struct inode * inode,
 		loff_t hole_size;
 		hole_size = file_off - inode->i_size;
 
-		printk("edward-176, Warning: Hole of size %llu in "
-		       "cryptcompress file (inode %llu, offset %llu) \n",
-		       hole_size, (unsigned long long)get_inode_oid(inode), file_off);
-
 		set_window(clust, win, inode, inode->i_size, file_off);
 		win->stat = HOLE_WINDOW;
 		if (win->off + hole_size < inode_cluster_size(inode))
@@ -2373,6 +2421,9 @@ write_cryptcompress_flow(struct file * f
 	assert("edward-749", reiser4_inode_data(inode)->cluster_shift <= MAX_CLUSTER_SHIFT);
 	assert("edward-1274", get_current_context()->grabbed_blocks == 0);
 
+	result = check_cryptcompress(inode);
+	if (result)
+		return result;
 	result = load_file_hint(file, &hint);
 	if (result)
 		return result;
@@ -2632,7 +2683,8 @@ set_append_cluster_key(const coord_t *co
    It succes was returned:
    (@index == 0 && @found == 0) means that the object doesn't have real disk
    clusters.
-   (@index != 0 && @found == 0) means that disk cluster of @index doesn't exist.
+   (@index != 0 && @found == 0) means that disk cluster of (@index -1 ) doesn't
+   exist.
 */
 static int
 find_real_disk_cluster(struct inode * inode, cloff_t * found, cloff_t index)
@@ -2878,13 +2930,9 @@ cryptcompress_append_hole(struct inode *
 	win.stat = HOLE_WINDOW;
 
 	assert("edward-1137", clust.index == off_to_clust(inode->i_size, inode));
-#if REISER4_DEBUG
-	printk("edward-1138, Warning: Hole of size %llu in "
-	       "cryptcompress file (inode %llu); "
-	       "%u zeroes appended to cluster (index = %lu) \n",
-	       hole_size, (unsigned long long)get_inode_oid(inode), nr_zeroes, clust.index);
-#endif
+
 	result = prepare_cluster(inode, 0, 0, &clust, PCL_APPEND);
+
 	assert("edward-1271", !result);
 	if (result)
 		goto out;
@@ -3045,12 +3093,12 @@ prune_cryptcompress(struct inode * inode
 	assert("edward-1191", inode->i_size == new_size);
 	assert("edward-1206", body_truncate_ok(inode, fidx));
  finish:
-	/* drop all the pages that don't have jnodes
-	   because of holes represented by fake disk clusters
-	   including the pages of partially truncated cluster
-	   which was released by prepare_cluster() */
-	truncate_inode_pages(inode->i_mapping,
-			     pg_to_off(count_to_nrpages(new_size)));
+	/* drop all the pages that don't have jnodes (i.e. pages
+	   which can not be truncated by cut_file_items() because
+	   of holes represented by fake disk clusters) including
+	   the pages of partially truncated cluster which was
+	   released by prepare_cluster() */
+	truncate_inode_pages(inode->i_mapping, new_size);
 	INODE_SET_FIELD(inode, i_size, new_size);
  out:
 	done_lh(&lh);
@@ -3089,13 +3137,20 @@ cryptcompress_truncate(struct inode *ino
 	       ergo(aidx > 0, inode->i_size > clust_to_off(aidx - 1, inode)));
 
 	if (truncating_last_fake_dc(inode, aidx, new_size)) {
-		/* we do not need to truncate items, so just drop pages
-		   which can not acquire jnodes because of exclusive access */
-
+		/* The last page cluster we truncate (fully or partially)
+		   is fake (don't have disk cluster) */
 		INODE_SET_FIELD(inode, i_size, new_size);
 		if (old_size > new_size) {
-			truncate_inode_pages(inode->i_mapping,
-					     pg_to_off(count_to_nrpages(new_size)));
+			/* Drop page cluster.
+			   There are only 2 cases for partially truncated page:
+			   1. If is is dirty, therefore it is anonymous
+			      (was dirtied via mmap), and will be captured
+			      later via ->capture().
+			   2. If is clean, therefore it is filled by zeroes.
+                           In both cases we don't need to make it dirty and
+			   capture here.
+			*/
+			truncate_inode_pages(inode->i_mapping, new_size);
 			assert("edward-663", ergo(!new_size,
 						  reiser4_inode_data(inode)->anonymous_eflushed == 0 &&
 						  reiser4_inode_data(inode)->captured_eflushed == 0));
@@ -3135,7 +3190,7 @@ capture_anonymous_cluster(reiser4_cluste
 	set_cluster_pages_dirty(clust);
 
 	result = try_capture_cluster(clust, inode);
-	set_hint_cluster(inode, clust->hint, clust->index + 1, ZNODE_WRITE_LOCK);
+	put_hint_cluster(clust, inode, ZNODE_WRITE_LOCK);
 	if (result)
 		release_cluster_pages_and_jnode(clust);
 	return result;
@@ -3149,14 +3204,15 @@ redirty_inode(struct inode *inode)
 	spin_unlock(&inode_lock);
 }
 
-#define CAPTURE_APAGE_BURST      (1024)
+#define MAX_CLUSTERS_TO_CAPTURE(inode)      (1024 >> inode_cluster_shift(inode))
 
+/* read lock should be acquired */
 static int
-capture_anonymous_clusters(struct address_space * mapping, pgoff_t * index)
+capture_anonymous_clusters(struct address_space * mapping, pgoff_t * index, int to_capture)
 {
 	int result = 0;
-	int to_capture;
 	int found;
+	int progress = 0;
 	struct page * page = NULL;
 	hint_t hint;
 	lock_handle lh;
@@ -3174,38 +3230,30 @@ capture_anonymous_clusters(struct addres
 	result = alloc_cluster_pgset(&clust, cluster_nrpages(mapping->host));
 	if (result)
 		goto out;
-	to_capture = (__u32)CAPTURE_APAGE_BURST >> inode_cluster_shift(mapping->host);
 
-	do {
+	while (to_capture > 0) {
 		found = find_get_pages_tag(mapping, index, PAGECACHE_TAG_REISER4_MOVED, 1, &page);
-		if (!found)
+		if (!found) {
+			*index = (pgoff_t) - 1;
 			break;
+		}
 		assert("edward-1109", page != NULL);
 
-		clust.index = pg_to_clust(*index, mapping->host);
-
+		move_cluster_forward(&clust, mapping->host, page->index, &progress);
 		result = capture_anonymous_cluster(&clust, mapping->host);
-		if (result) {
-			page_cache_release(page);
-			break;
-		}
 		page_cache_release(page);
+		if (result)
+			break;
 		to_capture --;
-
-		assert("edward-1076", clust.index <= pg_to_clust(*index, mapping->host));
-		/* index of the next cluster to capture */
-		if (clust.index == pg_to_clust(*index, mapping->host))
-			*index = clust_to_pg(clust.index + 1, mapping->host);
-	} while (to_capture);
-
+	}
 	if (result) {
 		warning("edward-1077", "Cannot capture anon pages: result=%i (captured=%d)\n",
 			result,
-			((__u32)CAPTURE_APAGE_BURST >> inode_cluster_shift(mapping->host)) - to_capture);
+			((__u32)MAX_CLUSTERS_TO_CAPTURE(mapping->host)) - to_capture);
 	} else {
 		/* something had to be found */
-		assert("edward-1078", to_capture <= CAPTURE_APAGE_BURST);
-		if (to_capture == 0)
+		assert("edward-1078", to_capture <= MAX_CLUSTERS_TO_CAPTURE(mapping->host));
+		if (to_capture <= 0)
 			/* there may be left more pages */
 			redirty_inode(mapping->host);
 	}
@@ -3229,6 +3277,8 @@ reiser4_internal int
 capture_cryptcompress(struct inode *inode, struct writeback_control *wbc)
 {
 	int result;
+	int to_capture;
+	pgoff_t nrpages;
 	pgoff_t index = 0;
 	cryptcompress_info_t * info;
 
@@ -3236,11 +3286,19 @@ capture_cryptcompress(struct inode *inod
 		return 0;
 
 	info = cryptcompress_inode_data(inode);
+	nrpages = (i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
 
+	if (wbc->sync_mode != WB_SYNC_ALL)
+		to_capture = min_count(wbc->nr_to_write, MAX_CLUSTERS_TO_CAPTURE(inode));
+	else
+		to_capture = MAX_CLUSTERS_TO_CAPTURE(inode);
 	do {
 		reiser4_context ctx;
 
 		if (is_in_reiser4_context()) {
+			/* FIXME-EDWARD: REMOVEME */
+			all_grabbed2free();
+
 			/* It can be in the context of write system call from
 			   balance_dirty_pages() */
 			if (down_read_trylock(&info->lock) == 0) {
@@ -3257,7 +3315,7 @@ capture_cryptcompress(struct inode *inod
 
 		LOCK_CNT_INC(inode_sem_r);
 
-		result = capture_anonymous_clusters(inode->i_mapping, &index);
+		result = capture_anonymous_clusters(inode->i_mapping, &index, to_capture);
 
 		up_read(&info->lock);
 
@@ -3269,7 +3327,7 @@ capture_cryptcompress(struct inode *inod
 		}
 		result = txnmgr_force_commit_all(inode->i_sb, 0);
 		reiser4_exit_context(&ctx);
-	} while (result == 0 && crc_inode_has_anon_pages(inode));
+	} while (result == 0 && index < nrpages);
 
 	return result;
 }
@@ -3365,6 +3423,9 @@ setattr_cryptcompress(struct inode *inod
 {
 	int result;
 
+	result = check_cryptcompress(inode);
+	if (result)
+		return result;
 	if (attr->ia_valid & ATTR_SIZE) {
 		/* EDWARD-FIXME-HANS: VS-FIXME-HANS:
 		   Q: this case occurs when? truncate?
diff -puN fs/reiser4/plugin/cryptcompress.h~reiser4-update fs/reiser4/plugin/cryptcompress.h
--- linux-2.6.12-rc2-mm3/fs/reiser4/plugin/cryptcompress.h~reiser4-update	2005-04-19 17:58:43.404941551 +0400
+++ linux-2.6.12-rc2-mm3-vs/fs/reiser4/plugin/cryptcompress.h	2005-04-19 17:58:43.502929472 +0400
@@ -16,6 +16,7 @@
 #define DEFAULT_CLUSTER_SHIFT 0
 #define DC_CHECKSUM_SIZE 4
 #define MIN_CRYPTO_BLOCKSIZE 8
+ //#define LAZY_COMPRESSION_MODE
 
 typedef unsigned long cloff_t;
 
diff -puN fs/reiser4/plugin/dir/dir.c~reiser4-update fs/reiser4/plugin/dir/dir.c
--- linux-2.6.12-rc2-mm3/fs/reiser4/plugin/dir/dir.c~reiser4-update	2005-04-19 17:58:43.409940934 +0400
+++ linux-2.6.12-rc2-mm3-vs/fs/reiser4/plugin/dir/dir.c	2005-04-19 17:58:43.504929226 +0400
@@ -141,8 +141,9 @@ link_common(struct inode *parent /* pare
 	 * For such inode we have to undo special processing done in
 	 * reiser4_unlink() viz. creation of safe-link.
 	 */
-	if (unlikely(inode_file_plugin(object)->not_linked(object))) {
-		result = safe_link_del(object, SAFE_UNLINK);
+	if (unlikely(object->i_nlink == 0)) {
+		result = safe_link_del(tree_by_inode(object),
+				       get_inode_oid(object), SAFE_UNLINK);
 		if (result != 0)
 			return result;
 	}
@@ -290,7 +291,7 @@ unlink_common(struct inode *parent /* pa
 			   marked for update. --SUS */
 			reiser4_update_dir(parent);
 			/* add safe-link for this file */
-			if (fplug->not_linked(object))
+			if (object->i_nlink == 0)
 				safe_link_add(object, SAFE_UNLINK);
 		}
 	}
diff -puN fs/reiser4/plugin/dir/hashed_dir.c~reiser4-update fs/reiser4/plugin/dir/hashed_dir.c
--- linux-2.6.12-rc2-mm3/fs/reiser4/plugin/dir/hashed_dir.c~reiser4-update	2005-04-19 17:58:43.414940318 +0400
+++ linux-2.6.12-rc2-mm3-vs/fs/reiser4/plugin/dir/hashed_dir.c	2005-04-19 17:58:43.506928979 +0400
@@ -1032,7 +1032,7 @@ rename_hashed(struct inode *old_dir /* d
 			/* add safe-link for target file (in case we removed
 			 * last reference to the poor fellow */
 			fplug = inode_file_plugin(new_inode);
-			if (fplug->not_linked(new_inode))
+			if (new_inode->i_nlink == 0)
 				result = safe_link_add(new_inode, SAFE_UNLINK);
 		}
 	}
diff -puN fs/reiser4/plugin/file/file.c~reiser4-update fs/reiser4/plugin/file/file.c
--- linux-2.6.12-rc2-mm3/fs/reiser4/plugin/file/file.c~reiser4-update	2005-04-19 17:58:43.419939702 +0400
+++ linux-2.6.12-rc2-mm3-vs/fs/reiser4/plugin/file/file.c	2005-04-19 17:58:43.508928733 +0400
@@ -2521,7 +2521,7 @@ setattr_truncate(struct inode *inode, st
 
 	s_result = safe_link_grab(tree, BA_CAN_COMMIT);
 	if (s_result == 0)
-		s_result = safe_link_del(inode, SAFE_TRUNCATE);
+		s_result = safe_link_del(tree, get_inode_oid(inode), SAFE_TRUNCATE);
 	if (s_result != 0) {
 		warning("nikita-3417", "Cannot kill safelink %lli: %i",
 			(unsigned long long)get_inode_oid(inode), s_result);
@@ -2578,14 +2578,31 @@ init_inode_data_unix_file(struct inode *
 	init_inode_ordering(inode, crd, create);
 }
 
-/* VS-FIXME-HANS: what is pre deleting all about? */
-/* 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
+   unallocated extents which do not have pages pointed by them (those pages are
+   removed by truncate_inode_pages), which may confuse flush code. The solution
+   for this problem is to call pre_delete method from reiser4_put_inode to
+   remove file items together with corresponding pages. Generic_delete_inode
+   will call truncate_inode_pages which will do nothing and
+   reiser4_delete_inode which completes file deletion by removing stat data
+   from the tree.
+   This method is to be called from reiser4_put_inode when file is already
+   unlinked and iput is about to drop last reference to inode.  If nfsd manages
+   to iget the file after pre_delete started, it will either be able to access
+   a file content (if it will get access to file earlier than pre_delete) or it
+   will get file truncated to 0 size if pre_delete goes first
+*/
 reiser4_internal int
 pre_delete_unix_file(struct inode *inode)
 {
 	unix_file_info_t *uf_info;
 	int result;
 
+	txn_restart_current();
+
 	/* FIXME: put comment here */
 	uf_info = unix_file_inode_data(inode);
 	get_exclusive_access(uf_info);
diff -puN fs/reiser4/plugin/item/ctail.c~reiser4-update fs/reiser4/plugin/item/ctail.c
--- linux-2.6.12-rc2-mm3/fs/reiser4/plugin/item/ctail.c~reiser4-update	2005-04-19 17:58:43.425938962 +0400
+++ linux-2.6.12-rc2-mm3-vs/fs/reiser4/plugin/item/ctail.c	2005-04-19 17:58:43.510928486 +0400
@@ -814,15 +814,8 @@ readpages_ctail(void *vp, struct address
 			continue;
 		}
 		unlock_page(page);
-		reset_cluster_params(&clust);
 
-		if (progress &&
-		    /* hole in the indices */
-		    pg_to_clust(page->index, inode) != clust.index + 1)
-			invalidate_hint_cluster(&clust);
-		progress++;
-
-		clust.index = pg_to_clust(page->index, inode);
+		move_cluster_forward(&clust, inode, page->index, &progress);
 		ret = ctail_read_page_cluster(&clust, inode);
 		if (ret)
 			goto exit;
diff -puN fs/reiser4/plugin/item/extent_file_ops.c~reiser4-update fs/reiser4/plugin/item/extent_file_ops.c
--- linux-2.6.12-rc2-mm3/fs/reiser4/plugin/item/extent_file_ops.c~reiser4-update	2005-04-19 17:58:43.430938346 +0400
+++ linux-2.6.12-rc2-mm3-vs/fs/reiser4/plugin/item/extent_file_ops.c	2005-04-19 17:58:43.513928117 +0400
@@ -7,6 +7,7 @@
 #include "../object.h"
 
 #include <linux/quotaops.h>
+#include <linux/swap.h>
 
 static inline reiser4_extent *
 ext_by_offset(const znode *node, int offset)
@@ -1173,6 +1174,10 @@ extent_readpage_filler(void *data, struc
 
 	hint = (hint_t *)data;
 	ext_coord = &hint->ext_coord;
+
+	BUG_ON(PageUptodate(page));
+	unlock_page(page);
+
 	if (hint_validate(hint, &key, 1/* check key */, ZNODE_READ_LOCK) != 0) {
 		result = coord_by_key(current_tree, &key, &ext_coord->coord,
 				      ext_coord->lh, ZNODE_READ_LOCK,
@@ -1180,6 +1185,7 @@ 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;
@@ -1188,6 +1194,7 @@ 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);
 	}
 
@@ -1197,8 +1204,14 @@ extent_readpage_filler(void *data, struc
 	assert("", (coord_extension_is_ok(ext_coord) &&
 		    coord_extension_is_ok2(ext_coord, &key)));
 
-	result = do_readpage_extent(ext_by_ext_coord(ext_coord),
-				    ext_coord->extension.extent.pos_in_unit, page);
+	lock_page(page);
+	if (!PageUptodate(page)) {
+		result = do_readpage_extent(ext_by_ext_coord(ext_coord),
+					    ext_coord->extension.extent.pos_in_unit, page);
+	} else {
+		unlock_page(page);
+		result = 0;
+	}
 	if (!result && move_coord_forward(ext_coord) == 0) {
 		set_key_offset(&key, offset + PAGE_CACHE_SIZE);
 		set_hint(hint, &key, ZNODE_READ_LOCK);
@@ -1217,22 +1230,49 @@ extent_readpages_hook(struct address_spa
 	read_cache_pages(mapping, pages, extent_readpage_filler, data);
 }
 
-static void
+static int
 call_page_cache_readahead(struct address_space *mapping, struct file *file,
 			  hint_t *hint,
 			  unsigned long page_nr,
-			  unsigned long ra_pages)
+			  unsigned long ra_pages,
+			  struct file_ra_state *ra)
 {
 	reiser4_file_fsdata *fsdata;
+	int result;
 
 	fsdata = reiser4_get_file_fsdata(file);
-	if (fsdata == NULL)
-		return;
+	if (IS_ERR(fsdata))
+		return page_nr;
 	fsdata->ra2.data = hint;
 	fsdata->ra2.readpages = extent_readpages_hook;
 
-	page_cache_readahead(mapping, &file->f_ra, file, page_nr, ra_pages);
+	result = page_cache_readahead(mapping, ra, file, page_nr, ra_pages);
 	fsdata->ra2.readpages = NULL;
+	return result;
+}
+
+
+/* this is called when readahead did not */
+static int
+call_readpage(struct file *file, struct page *page)
+{
+	int result;
+
+	result = readpage_unix_file(file, page);
+	if (result)
+		return result;
+
+	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);
+	}
+	return 0;
 }
 
 /* Implements plugin->u.item.s.file.read operation for extent items. */
@@ -1241,14 +1281,15 @@ read_extent(struct file *file, flow_t *f
 {
 	int result;
 	struct page *page;
-	unsigned long page_nr;
+	unsigned long cur_page, next_page;
 	unsigned long page_off, count;
 	struct address_space *mapping;
 	loff_t file_off;
 	uf_coord_t *uf_coord;
 	coord_t *coord;
 	extent_coord_extension_t *ext_coord;
-	unsigned long ra_pages;
+	unsigned long nr_pages, prev_page;
+	struct file_ra_state ra;
 
 	assert("vs-1353", current_blocksize == PAGE_CACHE_SIZE);
 	assert("vs-572", flow->user == 1);
@@ -1267,14 +1308,16 @@ read_extent(struct file *file, flow_t *f
 
 	/* offset in a file to start read from */
 	file_off = get_key_offset(&flow->key);
-	/* index of page containing that offset */
-	page_nr = (unsigned long)(file_off >> PAGE_CACHE_SHIFT);
 	/* offset within the page to start read from */
 	page_off = (unsigned long)(file_off & (PAGE_CACHE_SIZE - 1));
 	/* bytes which can be read from the page which contains file_off */
 	count = PAGE_CACHE_SIZE - page_off;
+
+	/* index of page containing offset read is to start from */
+	cur_page = (unsigned long)(file_off >> PAGE_CACHE_SHIFT);
+	next_page = cur_page;
 	/* number of pages flow spans over */
-	ra_pages = (flow->length + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+	nr_pages = ((file_off + flow->length + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT) - cur_page;
 
 	/* we start having twig node read locked. However, we do not want to
 	   keep that lock all the time readahead works. So, set a sel and
@@ -1282,26 +1325,50 @@ read_extent(struct file *file, flow_t *f
 	set_hint(hint, &flow->key, ZNODE_READ_LOCK);
 	longterm_unlock_znode(hint->ext_coord.lh);
 
+	ra = file->f_ra;
+	prev_page = ra.prev_page;
 	do {
-		call_page_cache_readahead(mapping, file, hint, page_nr, ra_pages);
+		if (next_page == cur_page)
+			next_page = call_page_cache_readahead(mapping, file, hint, cur_page, nr_pages, &ra);
 
-		/* this will return page if it exists and is uptodate,
-		   otherwise it will allocate page and call readpage_extent to
-		   fill it */
-		page = read_cache_page(mapping, page_nr, readpage_unix_file, file);
-		if (IS_ERR(page))
-			return PTR_ERR(page);
-
-		wait_on_page_locked(page);
-		if (!PageUptodate(page)) {
-			page_detach_jnode(page, mapping, page_nr);
-			page_cache_release(page);
-			warning("jmacd-97178", "extent_read: page is not up to date");
-			return RETERR(-EIO);
+		page = find_get_page(mapping, cur_page);
+		if (unlikely(page == NULL)) {
+			handle_ra_miss(mapping, &ra, cur_page);
+			page = read_cache_page(mapping, cur_page, readpage_unix_file, file);
+			if (IS_ERR(page))
+				return PTR_ERR(page);
+			lock_page(page);
+			if (!PageUptodate(page)) {
+				unlock_page(page);
+				page_detach_jnode(page, mapping, cur_page);
+				page_cache_release(page);
+				warning("jmacd-97178", "extent_read: page is not up to date");
+				return RETERR(-EIO);
+			}
+			unlock_page(page);
+		} else {
+			if (!PageUptodate(page)) {
+				lock_page(page);
+				
+				assert("", page->mapping == mapping);
+				if (PageUptodate(page))
+					unlock_page(page);
+				else {
+					result = call_readpage(file, page);
+					if (result) {
+						page_cache_release(page);
+						return RETERR(result);
+					}
+				}
+			}
+			if (prev_page != cur_page)
+				mark_page_accessed(page);
+			prev_page = cur_page;
 		}
 
-		/* If users can be writing to this page using arbitrary virtual addresses, take care about potential
-		   aliasing before reading the page on the kernel side.
+		/* If users can be writing to this page using arbitrary virtual
+		   addresses, take care about potential aliasing before reading
+		   the page on the kernel side.
 		*/
 		if (mapping_writably_mapped(mapping))
 			flush_dcache_page(page);
@@ -1324,11 +1391,12 @@ read_extent(struct file *file, flow_t *f
 		move_flow_forward(flow, count);
 
 		page_off = 0;
-		page_nr ++;
+		cur_page ++;
 		count = PAGE_CACHE_SIZE;
-		ra_pages --;
+		nr_pages --;
 	} while (flow->length);
 
+	file->f_ra = ra;
 	return 0;
 }
 
diff -puN fs/reiser4/plugin/object.c~reiser4-update fs/reiser4/plugin/object.c
--- linux-2.6.12-rc2-mm3/fs/reiser4/plugin/object.c~reiser4-update	2005-04-19 17:58:43.435937730 +0400
+++ linux-2.6.12-rc2-mm3-vs/fs/reiser4/plugin/object.c	2005-04-19 17:58:43.515927870 +0400
@@ -507,7 +507,9 @@ common_object_delete_no_reserve(struct i
 			if (result == 0) {
 				oid_count_released();
 
-				result = safe_link_del(inode, SAFE_UNLINK);
+				result = safe_link_del(tree_by_inode(inode),
+						       get_inode_oid(inode),
+						       SAFE_UNLINK);
 			}
 		}
 	} else
@@ -741,21 +743,21 @@ rem_link_common(struct inode *object, st
 	return 0;
 }
 
-/* ->not_linked() method for file plugins */
+/* default (for directories) ->rem_link() method of file plugin */
 static int
-not_linked_common(const struct inode *inode)
+rem_link_common_dir(struct inode *object, struct inode *parent UNUSED_ARG)
 {
-	assert("nikita-2007", inode != NULL);
-	return (inode->i_nlink == 0);
-}
+	assert("nikita-20211", object != NULL);
+	assert("nikita-21631", object->i_nlink > 0);
 
-/* ->not_linked() method the for directory file plugin */
-static int
-not_linked_dir(const struct inode *inode)
-{
-	assert("nikita-2008", inode != NULL);
-	/* one link from dot */
-	return (inode->i_nlink == 1);
+	/*
+	 * decrement ->i_nlink and update ->i_ctime
+	 */
+	INODE_DEC_FIELD(object, i_nlink);
+	if (object->i_nlink == 1)
+		INODE_DEC_FIELD(object, i_nlink);
+	object->i_ctime = CURRENT_TIME;
+	return 0;
 }
 
 /* ->adjust_to_parent() method for regular files */
@@ -954,102 +956,6 @@ setattr_common(struct inode *inode /* Ob
 	return result;
 }
 
-/* doesn't seem to be exported in headers. */
-extern spinlock_t inode_lock;
-
-/* ->delete_inode() method. This is called by
- * iput()->iput_final()->drop_inode() when last reference to inode is released
- * and inode has no names. */
-static void delete_inode_common(struct inode *object)
-{
-	/* create context here.
-	 *
-	 * removal of inode from the hash table (done at the very beginning of
-	 * generic_delete_inode(), truncate of pages, and removal of file's
-	 * extents has to be performed in the same atom. Otherwise, it may so
-	 * happen, that twig node with unallocated extent will be flushed to
-	 * the disk.
-	 */
-	reiser4_context ctx;
-
-	/*
-	 * FIXME: this resembles generic_delete_inode
-	 */
-	list_del_init(&object->i_list);
-	list_del_init(&object->i_sb_list);
-	object->i_state |= I_FREEING;
-	inodes_stat.nr_inodes--;
-	spin_unlock(&inode_lock);
-
-	init_context(&ctx, object->i_sb);
-
-	kill_cursors(object);
-
-	if (!is_bad_inode(object)) {
-		file_plugin *fplug;
-
-		/* truncate object body */
-		fplug = inode_file_plugin(object);
-		if (fplug->pre_delete != NULL && fplug->pre_delete(object) != 0)
-			warning("vs-1216", "Failed to delete file body %llu",
-				(unsigned long long)get_inode_oid(object));
-		else
-			assert("vs-1430",
-			       reiser4_inode_data(object)->anonymous_eflushed == 0 &&
-			       reiser4_inode_data(object)->captured_eflushed == 0);
-	}
-
-	if (object->i_data.nrpages) {
-		warning("vs-1434", "nrpages %ld\n", object->i_data.nrpages);
-		truncate_inode_pages(&object->i_data, 0);
-	}
-	security_inode_delete(object);
-	if (!is_bad_inode(object))
-		DQUOT_INIT(object);
-
-	object->i_sb->s_op->delete_inode(object);
-
-	spin_lock(&inode_lock);
-	hlist_del_init(&object->i_hash);
-	spin_unlock(&inode_lock);
-	wake_up_inode(object);
-	if (object->i_state != I_CLEAR)
-		BUG();
-	destroy_inode(object);
-	reiser4_exit_context(&ctx);
-}
-
-/*
- * ->forget_inode() method. Called by iput()->iput_final()->drop_inode() when
- * last reference to inode with names is released
- */
-static void forget_inode_common(struct inode *object)
-{
-	generic_forget_inode(object);
-}
-
-/* ->drop_inode() method. Called by iput()->iput_final() when last reference
- * to inode is released */
-static void drop_common(struct inode * object)
-{
-	file_plugin *fplug;
-
-	assert("nikita-2643", object != NULL);
-
-	/* -not- creating context in this method, because it is frequently
-	   called and all existing ->not_linked() methods are one liners. */
-
-	fplug = inode_file_plugin(object);
-	/* fplug is NULL for fake inode */
-	if (fplug != NULL && fplug->not_linked(object)) {
-		assert("nikita-3231", fplug->delete_inode != NULL);
-		fplug->delete_inode(object);
-	} else {
-		assert("nikita-3232", fplug->forget_inode != NULL);
-		fplug->forget_inode(object);
-	}
-}
-
 static ssize_t
 isdir(void)
 {
@@ -1293,7 +1199,6 @@ file_plugin file_plugins[LAST_FILE_PLUGI
 		.owns_item = owns_item_unix_file,
 		.can_add_link = can_add_link_common,
 		.can_rem_link = NULL,
-		.not_linked = not_linked_common,
 		.setattr = setattr_unix_file,
 		.getattr = getattr_common,
 		.seek = NULL,
@@ -1315,10 +1220,7 @@ file_plugin file_plugins[LAST_FILE_PLUGI
 		.init_inode_data = init_inode_data_unix_file,
 		.pre_delete = pre_delete_unix_file,
 		.cut_tree_worker = cut_tree_worker_common,
-		.drop = drop_common,
-		.delete_inode = delete_inode_common,
 		.destroy_inode = NULL,
-		.forget_inode = forget_inode_common,
 		.sendfile = sendfile_unix_file,
 		.prepare_write = prepare_write_unix_file
 	},
@@ -1350,11 +1252,10 @@ file_plugin file_plugins[LAST_FILE_PLUGI
 		.delete = delete_directory_common,
 		.sync = sync_common,
 		.add_link = add_link_common,
-		.rem_link = rem_link_common,
+		.rem_link = rem_link_common_dir,
 		.owns_item = owns_item_hashed,
 		.can_add_link = can_add_link_common,
 		.can_rem_link = can_rem_dir,
-		.not_linked = not_linked_dir,
 		.setattr = setattr_common,
 		.getattr = getattr_common,
 		.seek = seek_dir,
@@ -1376,10 +1277,7 @@ file_plugin file_plugins[LAST_FILE_PLUGI
 		.init_inode_data = init_inode_ordering,
 		.pre_delete = NULL,
 		.cut_tree_worker = cut_tree_worker_common,
-		.drop = drop_common,
-		.delete_inode = delete_inode_common,
 		.destroy_inode = NULL,
-		.forget_inode = forget_inode_common,
 	},
 	[SYMLINK_FILE_PLUGIN_ID] = {
 		.h = {
@@ -1416,7 +1314,6 @@ file_plugin file_plugins[LAST_FILE_PLUGI
 		.owns_item = NULL,
 		.can_add_link = can_add_link_common,
 		.can_rem_link = NULL,
-		.not_linked = not_linked_common,
 		.setattr = setattr_common,
 		.getattr = getattr_common,
 		.seek = NULL,
@@ -1438,10 +1335,7 @@ file_plugin file_plugins[LAST_FILE_PLUGI
 		.init_inode_data = init_inode_ordering,
 		.pre_delete = NULL,
 		.cut_tree_worker = cut_tree_worker_common,
-		.drop = drop_common,
-		.delete_inode = delete_inode_common,
 		.destroy_inode = destroy_inode_symlink,
-		.forget_inode = forget_inode_common,
 	},
 	[SPECIAL_FILE_PLUGIN_ID] = {
 		.h = {
@@ -1476,7 +1370,6 @@ file_plugin file_plugins[LAST_FILE_PLUGI
 		.owns_item = owns_item_common,
 		.can_add_link = can_add_link_common,
 		.can_rem_link = NULL,
-		.not_linked = not_linked_common,
 		.setattr = setattr_common,
 		.getattr = getattr_common,
 		.seek = NULL,
@@ -1498,10 +1391,7 @@ file_plugin file_plugins[LAST_FILE_PLUGI
 		.init_inode_data = init_inode_ordering,
 		.pre_delete = NULL,
 		.cut_tree_worker = cut_tree_worker_common,
-		.drop = drop_common,
-		.delete_inode = delete_inode_common,
 		.destroy_inode = NULL,
-		.forget_inode = forget_inode_common,
 	},
 	[PSEUDO_FILE_PLUGIN_ID] = {
 		.h = {
@@ -1536,7 +1426,6 @@ file_plugin file_plugins[LAST_FILE_PLUGI
 		.owns_item         = NULL,
 		.can_add_link      = cannot,
 		.can_rem_link      = cannot,
-		.not_linked        = NULL,
 		.setattr           = inode_setattr,
 		.getattr           = getattr_common,
 		.seek              = seek_pseudo,
@@ -1558,10 +1447,7 @@ file_plugin file_plugins[LAST_FILE_PLUGI
 		.init_inode_data = NULL,
 		.pre_delete = NULL,
 		.cut_tree_worker = cut_tree_worker_common,
-		.drop = drop_pseudo,
-		.delete_inode = NULL,
 		.destroy_inode = NULL,
-		.forget_inode = NULL,
 	},
 	[CRC_FILE_PLUGIN_ID] = {
 		.h = {
@@ -1597,7 +1483,6 @@ file_plugin file_plugins[LAST_FILE_PLUGI
 		.owns_item = owns_item_common,
 		.can_add_link = can_add_link_common,
 		.can_rem_link = NULL,
-		.not_linked = not_linked_common,
 		.setattr = setattr_cryptcompress,
 		.getattr = getattr_common,
 		.seek = NULL,
@@ -1620,10 +1505,7 @@ file_plugin file_plugins[LAST_FILE_PLUGI
 		.init_inode_data = init_inode_data_cryptcompress,
 		.pre_delete = pre_delete_cryptcompress,
 		.cut_tree_worker = cut_tree_worker_cryptcompress,
-		.drop = drop_common,
-		.delete_inode = delete_inode_common,
 		.destroy_inode = destroy_inode_cryptcompress,
-		.forget_inode = forget_inode_common,
 		.sendfile = sendfile_common,
 		.prepare_write = prepare_write_common
 	}
diff -puN fs/reiser4/plugin/plugin.h~reiser4-update fs/reiser4/plugin/plugin.h
--- linux-2.6.12-rc2-mm3/fs/reiser4/plugin/plugin.h~reiser4-update	2005-04-19 17:58:43.441936990 +0400
+++ linux-2.6.12-rc2-mm3-vs/fs/reiser4/plugin/plugin.h	2005-04-19 17:58:43.517927624 +0400
@@ -238,8 +238,6 @@ Elena doing this for you if that helps. 
 	int (*can_add_link) (const struct inode * inode);
 	/* checks whether hard links to this object can be removed */
 	int (*can_rem_link) (const struct inode * inode);
-	/* true if there is only one link (aka name) for this file */
-	int (*not_linked) (const struct inode * inode);
 
 	/* change inode attributes. */
 	int (*setattr) (struct inode * inode, struct iattr * attr);
@@ -293,16 +291,9 @@ Elena doing this for you if that helps. 
 	/* truncate file to zero size. called by reiser4_drop_inode before truncate_inode_pages */
 	int (*pre_delete)(struct inode *);
 
-	/* called from reiser4_drop_inode() */
-	void (*drop)(struct inode *);
-
-	/* called from ->drop() when there are no links, and object should be
-	 * garbage collected. */
-	void (*delete_inode)(struct inode *);
-
 	/* called from ->destroy_inode() */
 	void (*destroy_inode)(struct inode *);
-	void (*forget_inode)(struct inode *);
+
 	ssize_t (*sendfile)(struct file *, loff_t *, size_t, read_actor_t, void __user *);
 	/*
 	 * methods to serialize object identify. This is used, for example, by
@@ -453,6 +444,9 @@ typedef struct digest_plugin {
 typedef struct compression_plugin {
 	/* generic fields */
 	plugin_header h;
+	/* id of the dual plugin */
+	reiser4_compression_id dual;
+	int (*init) (void);
 	/* the maximum number of bytes the size of the "compressed" data can
 	 * exceed the uncompressed data. */
 	int (*overrun) (unsigned src_len);
diff -puN fs/reiser4/safe_link.c~reiser4-update fs/reiser4/safe_link.c
--- linux-2.6.12-rc2-mm3/fs/reiser4/safe_link.c~reiser4-update	2005-04-19 17:58:43.445936498 +0400
+++ linux-2.6.12-rc2-mm3-vs/fs/reiser4/safe_link.c	2005-04-19 17:58:43.519927377 +0400
@@ -91,11 +91,12 @@ safe_link_locality(reiser4_tree *tree)
 
  */
 static reiser4_key *
-build_link_key(struct inode *inode, reiser4_safe_link_t link, reiser4_key *key)
+build_link_key(reiser4_tree *tree, oid_t oid, reiser4_safe_link_t link,
+	       reiser4_key *key)
 {
 	reiser4_key_init(key);
-	set_key_locality(key, safe_link_locality(tree_by_inode(inode)));
-	set_key_objectid(key, get_inode_oid(inode));
+	set_key_locality(key, safe_link_locality(tree));
+	set_key_objectid(key, oid);
 	set_key_offset(key, link);
 	return key;
 }
@@ -171,7 +172,7 @@ reiser4_internal int safe_link_add(struc
 		cputod64(inode->i_size, &sl.size);
 	}
 	tree = tree_by_inode(inode);
-	build_link_key(inode, link, &key);
+	build_link_key(tree, get_inode_oid(inode), link, &key);
 
 	result = store_black_box(tree, &key, &sl, length);
 	if (result == -EEXIST)
@@ -183,12 +184,13 @@ reiser4_internal int safe_link_add(struc
  * remove safe-link corresponding to the operation @link on inode @inode from
  * the tree.
  */
-reiser4_internal int safe_link_del(struct inode *inode, reiser4_safe_link_t link)
+reiser4_internal int
+safe_link_del(reiser4_tree *tree, oid_t oid, reiser4_safe_link_t link)
 {
 	reiser4_key key;
 
-	return kill_black_box(tree_by_inode(inode),
-			      build_link_key(inode, link, &key));
+	return kill_black_box(tree,
+			      build_link_key(tree, oid, link, &key));
 }
 
 /*
@@ -273,6 +275,7 @@ static int process_safelink(struct super
 
 		fplug = inode_file_plugin(inode);
 		assert("nikita-3428", fplug != NULL);
+		assert("", oid == get_inode_oid(inode));
 		if (fplug->safelink != NULL) {
 			/* txn_restart_current is not necessary because
 			 * mounting is signle thread. However, without it
@@ -295,11 +298,11 @@ static int process_safelink(struct super
 		reiser4_iget_complete(inode);
 		iput(inode);
 		if (result == 0) {
-			result = safe_link_grab(tree_by_inode(inode),
+			result = safe_link_grab(get_tree(super),
 						BA_CAN_COMMIT);
 			if (result == 0)
-				result = safe_link_del(inode, link);
-			safe_link_release(tree_by_inode(inode));
+				result = safe_link_del(get_tree(super), oid, link);
+			safe_link_release(get_tree(super));
 			/*
 			 * restart transaction: if there was large number of
 			 * safe-links, their processing may fail to fit into
diff -puN fs/reiser4/safe_link.h~reiser4-update fs/reiser4/safe_link.h
--- linux-2.6.12-rc2-mm3/fs/reiser4/safe_link.h~reiser4-update	2005-04-19 17:58:43.450935881 +0400
+++ linux-2.6.12-rc2-mm3-vs/fs/reiser4/safe_link.h	2005-04-19 17:58:43.519927377 +0400
@@ -11,7 +11,7 @@
 int safe_link_grab(reiser4_tree *tree, reiser4_ba_flags_t flags);
 void safe_link_release(reiser4_tree *tree);
 int safe_link_add(struct inode *inode, reiser4_safe_link_t link);
-int safe_link_del(struct inode *inode, reiser4_safe_link_t link);
+int safe_link_del(reiser4_tree *, oid_t oid, reiser4_safe_link_t link);
 
 int process_safelinks(struct super_block *super);
 
diff -puN fs/reiser4/tree.c~reiser4-update fs/reiser4/tree.c
--- linux-2.6.12-rc2-mm3/fs/reiser4/tree.c~reiser4-update	2005-04-19 17:58:43.455935265 +0400
+++ linux-2.6.12-rc2-mm3-vs/fs/reiser4/tree.c	2005-04-19 17:58:43.521927131 +0400
@@ -1400,7 +1400,7 @@ reiser4_internal int delete_node (znode 
 
 	init_lh(&parent_lock);
 
-	ret = reiser4_get_parent(&parent_lock, node, ZNODE_WRITE_LOCK, 0);
+	ret = reiser4_get_parent(&parent_lock, node, ZNODE_WRITE_LOCK);
 	if (ret)
 		return ret;
 
diff -puN fs/reiser4/tree_walk.c~reiser4-update fs/reiser4/tree_walk.c
--- linux-2.6.12-rc2-mm3/fs/reiser4/tree_walk.c~reiser4-update	2005-04-19 17:58:43.460934649 +0400
+++ linux-2.6.12-rc2-mm3-vs/fs/reiser4/tree_walk.c	2005-04-19 17:58:43.523926884 +0400
@@ -137,27 +137,6 @@ reiser4_get_parent_flags(lock_handle * r
 				      ZNODE_LOCK_HIPRI, flags, 1));
 }
 
-/* A wrapper for reiser4_get_parent_flags(). */
-reiser4_internal int
-reiser4_get_parent(lock_handle * result	/* resulting lock
-					   * handle */ ,
-		   znode * node /* child node */ ,
-		   znode_lock_mode mode /* type of lock: read or write */ ,
-		   int only_connected_p	/* if this is true, parent is
-					 * only returned when it is
-					 * connected. If parent is
-					 * unconnected, -E_NO_NEIGHBOR is
-					 * returned. Normal users should
-					 * pass 1 here. Only during carry
-					 * we want to access still
-					 * unconnected parents. */ )
-{
-	assert("umka-238", znode_get_tree(node) != NULL);
-
-	return reiser4_get_parent_flags(result, node, mode,
-					only_connected_p ? 0 : GN_ALLOW_NOT_CONNECTED);
-}
-
 /* wrapper function to lock right or left neighbor depending on GN_GO_LEFT
    bit in @flags parameter  */
 /* Audited by: umka (2002.06.14) */
@@ -705,7 +684,7 @@ again:
 	/* before establishing of sibling link we lock parent node; it is
 	   required by renew_neighbor() to work.  */
 	init_lh(&path[0]);
-	ret = reiser4_get_parent(&path[0], node, ZNODE_READ_LOCK, 1);
+	ret = reiser4_get_parent(&path[0], node, ZNODE_READ_LOCK);
 	if (ret)
 		return ret;
 	if (znode_above_root(path[0].node)) {
@@ -753,7 +732,7 @@ again:
 			/* sibling link is not available -- we go
 			   upward. */
 			init_lh(&path[h + 1]);
-			ret = reiser4_get_parent(&path[h + 1], parent, ZNODE_READ_LOCK, 1);
+			ret = reiser4_get_parent(&path[h + 1], parent, ZNODE_READ_LOCK);
 			if (ret)
 				goto fail;
 			++h;
@@ -1034,7 +1013,7 @@ static int tw_up (struct tw_handle * h)
 	init_load_count(&load);
 
 	do {
-		ret = reiser4_get_parent(&lock, h->tap.lh->node, ZNODE_WRITE_LOCK, 0);
+		ret = reiser4_get_parent(&lock, h->tap.lh->node, ZNODE_WRITE_LOCK);
 		if (ret)
 			break;
 		if (znode_above_root(lock.node)) {
diff -puN fs/reiser4/tree_walk.h~reiser4-update fs/reiser4/tree_walk.h
--- linux-2.6.12-rc2-mm3/fs/reiser4/tree_walk.h~reiser4-update	2005-04-19 17:58:43.464934156 +0400
+++ linux-2.6.12-rc2-mm3-vs/fs/reiser4/tree_walk.h	2005-04-19 17:58:43.524926761 +0400
@@ -37,8 +37,6 @@ int
 reiser4_get_parent_flags(lock_handle * result, znode * node,
 			 znode_lock_mode mode, int flags);
 
-int reiser4_get_parent(lock_handle * result, znode * node, znode_lock_mode mode, int only_connected_p);
-
 /* bits definition for reiser4_get_neighbor function `flags' arg. */
 typedef enum {
 	/* If sibling pointer is NULL, this flag allows get_neighbor() to try to
@@ -62,6 +60,13 @@ typedef enum {
 	GN_ASYNC = 0x80
 } znode_get_neigbor_flags;
 
+/* A commonly used wrapper for reiser4_get_parent_flags(). */
+static inline int reiser4_get_parent(
+	lock_handle * result, znode * node, znode_lock_mode mode)
+{
+	return reiser4_get_parent_flags(result, node, mode, GN_ALLOW_NOT_CONNECTED);
+}
+
 int reiser4_get_neighbor(lock_handle * neighbor, znode * node, znode_lock_mode lock_mode, int flags);
 
 /* there are wrappers for most common usages of reiser4_get_neighbor() */
diff -puN fs/reiser4/txnmgr.c~reiser4-update fs/reiser4/txnmgr.c
--- linux-2.6.12-rc2-mm3/fs/reiser4/txnmgr.c~reiser4-update	2005-04-19 17:58:43.470933416 +0400
+++ linux-2.6.12-rc2-mm3-vs/fs/reiser4/txnmgr.c	2005-04-19 17:58:43.527926391 +0400
@@ -1380,6 +1380,51 @@ commit_some_atoms(txn_mgr * mgr)
 	return 0;
 }
 
+static int txn_try_to_fuse_small_atom (txn_mgr * tmgr, txn_atom * atom)
+{
+	int atom_stage;
+	txn_atom *atom_2;
+	int repeat;
+	
+	assert ("zam-1051", atom->stage < ASTAGE_PRE_COMMIT);
+
+	atom_stage = atom->stage;
+	repeat = 0;
+
+	if (!spin_trylock_txnmgr(tmgr)) {
+		UNLOCK_ATOM(atom);
+		spin_lock_txnmgr(tmgr);
+		LOCK_ATOM(atom);
+		repeat = 1;
+		if (atom->stage != atom_stage)
+			goto out;
+	}
+
+	for_all_type_safe_list(atom, &tmgr->atoms_list, atom_2) {
+		if (atom == atom_2)
+			continue;
+		/* if trylock does not succeed we just do not fuse with that
+		 * atom. */
+		if (spin_trylock_atom(atom_2)) {
+			if (atom_2->stage < ASTAGE_PRE_COMMIT) {
+				spin_unlock_txnmgr(tmgr);
+				capture_fuse_into(atom_2, atom);
+				/* all locks are lost we can only repeat here */
+				return -E_REPEAT;
+			}
+			UNLOCK_ATOM(atom_2);
+		}
+	}
+	spin_unlock_txnmgr(tmgr);
+	atom->flags |= ATOM_CANCEL_FUSION;
+ out: 
+	if (repeat) {
+		UNLOCK_ATOM(atom);
+		return -E_REPEAT;
+	}
+	return 0;
+}
+
 /* Calls jnode_flush for current atom if it exists; if not, just take another
    atom and call jnode_flush() for him.  If current transaction handle has
    already assigned atom (current atom) we have to close current transaction
@@ -1397,6 +1442,7 @@ reiser4_internal int
 flush_some_atom(long *nr_submitted, const struct writeback_control *wbc, int flags)
 {
 	reiser4_context *ctx = get_current_context();
+	txn_mgr *tmgr = &get_super_private(ctx->super)->tmgr;
 	txn_handle *txnh = ctx->trans;
 	txn_atom *atom;
 	int ret;
@@ -1406,8 +1452,6 @@ flush_some_atom(long *nr_submitted, cons
  repeat:
 	if (txnh->atom == NULL) {
 		/* current atom is available, take first from txnmgr */
-		txn_mgr *tmgr = &get_super_private(ctx->super)->tmgr;
-
 		spin_lock_txnmgr(tmgr);
 
 		/* traverse the list of all atoms */
@@ -1463,6 +1507,12 @@ 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 && 
+			    !(atom->flags & ATOM_CANCEL_FUSION)) {
+				ret =txn_try_to_fuse_small_atom(tmgr, atom);
+				if (ret == -E_REPEAT)
+					goto repeat;
+			}
 			/* if early flushing could not make more nodes clean,
 			 * or atom is too old/large,
 			 * we force current atom to commit */
diff -puN fs/reiser4/txnmgr.h~reiser4-update fs/reiser4/txnmgr.h
--- linux-2.6.12-rc2-mm3/fs/reiser4/txnmgr.h~reiser4-update	2005-04-19 17:58:43.475932800 +0400
+++ linux-2.6.12-rc2-mm3-vs/fs/reiser4/txnmgr.h	2005-04-19 17:58:43.529926145 +0400
@@ -161,7 +161,10 @@ typedef enum {
 /* Certain flags may be set in the txn_atom->flags field. */
 typedef enum {
 	/* Indicates that the atom should commit as soon as possible. */
-	ATOM_FORCE_COMMIT = (1 << 0)
+	ATOM_FORCE_COMMIT = (1 << 0),
+	/* to avoid endless loop, mark the atom (which was considered as too
+	 * small) after failed attempt to fuse it. */
+	ATOM_CANCEL_FUSION = (1 << 1)
 } txn_flags;
 
 /* Flags for controlling commit_txnh */
@@ -434,6 +437,7 @@ struct txn_mgr {
 	/* parameters. Adjustable through mount options. */
 	unsigned int atom_max_size;
 	unsigned int atom_max_age;
+	unsigned int atom_min_size;
 	/* max number of concurrent flushers for one atom, 0 - unlimited.  */
 	unsigned int atom_max_flushers;
 };
diff -puN fs/reiser4/vfs_ops.c~reiser4-update fs/reiser4/vfs_ops.c
--- linux-2.6.12-rc2-mm3/fs/reiser4/vfs_ops.c~reiser4-update	2005-04-19 17:58:43.480932184 +0400
+++ linux-2.6.12-rc2-mm3-vs/fs/reiser4/vfs_ops.c	2005-04-19 17:58:43.531925898 +0400
@@ -56,14 +56,14 @@
 
 /* super operations */
 
-static struct inode *reiser4_alloc_inode(struct super_block *super);
-static void reiser4_destroy_inode(struct inode *inode);
-static void reiser4_drop_inode(struct inode *);
+static struct inode *reiser4_alloc_inode(struct super_block *);
+static void reiser4_destroy_inode(struct inode *);
+static void reiser4_put_inode(struct inode *);
 static void reiser4_delete_inode(struct inode *);
 static void reiser4_write_super(struct super_block *);
 static int reiser4_statfs(struct super_block *, struct kstatfs *);
 static int reiser4_show_options(struct seq_file *m, struct vfsmount *mnt);
-static void reiser4_sync_inodes(struct super_block *s, struct writeback_control * wbc);
+static void reiser4_sync_inodes(struct super_block *, struct writeback_control *);
 
 extern struct dentry_operations reiser4_dentry_operation;
 
@@ -530,25 +530,29 @@ reiser4_destroy_inode(struct inode *inod
 	kmem_cache_free(inode_cache, container_of(info, reiser4_inode_object, p));
 }
 
-/* our ->drop_inode() method. This is called by iput_final() when last
- * reference on inode is released */
+/* 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
+   0. */
 static void
-reiser4_drop_inode(struct inode *object)
+reiser4_put_inode(struct inode *inode)
 {
+	reiser4_context ctx;
 	file_plugin *fplug;
 
-	assert("nikita-2643", object != NULL);
-
-	/* -not- creating context in this method, because it is frequently
-	   called and all existing ->not_linked() methods are one liners. */
+	fplug = inode_file_plugin(inode);
+	if (fplug == NULL || 
+	    inode->i_nlink != 0 ||
+	    atomic_read(&inode->i_count) > 1 ||
+	    fplug->pre_delete == NULL)
+		return;
 
-	fplug = inode_file_plugin(object);
-	/* fplug is NULL for fake inode */
-	if (fplug != NULL) {
-		assert("nikita-3251", fplug->drop != NULL);
-		fplug->drop(object);
-	} else
-		generic_forget_inode(object);
+	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);	
+	reiser4_exit_context(&ctx);
 }
 
 /*
@@ -955,6 +959,12 @@ do {						\
 	decimal.
 	*/
 	PUSH_SB_FIELD_OPT(tmgr.atom_max_age, "%u");
+	/* tmgr.atom_min_size=N
+
+	In committing an atom to free dirty pages, force the atom less than N in
+	size to fuse with another one.
+	 */
+	PUSH_SB_FIELD_OPT(tmgr.atom_min_size, "%u");
 	/* tmgr.atom_max_flushers=N
 
 	limit of concurrent flushers for one atom. 0 means no limit.
@@ -1047,6 +1057,7 @@ do {						\
 
 	sbinfo->tmgr.atom_max_size = txnmgr_get_max_atom_size(s);
 	sbinfo->tmgr.atom_max_age = REISER4_ATOM_MAX_AGE / HZ;
+	sbinfo->tmgr.atom_min_size = 256;
 	sbinfo->tmgr.atom_max_flushers = ATOM_MAX_FLUSHERS;
 
 	sbinfo->tree.cbk_cache.nr_slots = CBK_CACHE_SLOTS;
@@ -1351,8 +1362,8 @@ struct super_operations reiser4_super_op
 	.read_inode = noop_read_inode,
 	.dirty_inode = NULL,
  	.write_inode = NULL,
- 	.put_inode = NULL,
-	.drop_inode = reiser4_drop_inode,
+ 	.put_inode = reiser4_put_inode,
+	.drop_inode = NULL,
 	.delete_inode = reiser4_delete_inode,
 	.put_super = reiser4_put_super,
 	.write_super = reiser4_write_super,

_
