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,

_