 fs/reiser4/plugin/file/cryptcompress.c |    7 ++
 fs/reiser4/plugin/file/file.c          |   79 ++++++++++++++++++++-------------
 fs/reiser4/plugin/file/file.h          |    3 -
 fs/reiser4/plugin/file_plugin_common.c |   12 +----
 fs/reiser4/plugin/object.c             |    4 +
 fs/reiser4/plugin/plugin.h             |   11 ++--
 fs/reiser4/super.c                     |    1 
 fs/reiser4/super_ops.c                 |   31 ++++++++++++
 8 files changed, 102 insertions(+), 46 deletions(-)

diff -puN fs/reiser4/plugin/file/cryptcompress.c~reiser4-add-put_inode fs/reiser4/plugin/file/cryptcompress.c
--- linux-2.6.13/fs/reiser4/plugin/file/cryptcompress.c~reiser4-add-put_inode	2005-10-03 16:00:01.000000000 +0400
+++ linux-2.6.13-vs/fs/reiser4/plugin/file/cryptcompress.c	2005-10-03 16:02:00.000000000 +0400
@@ -3441,6 +3441,13 @@ int delete_cryptcompress(struct inode *i
 	return delete_object_common(inode);
 }
 
+/* plugin->u.file.pre_delete method
+   see plugin.h for description */
+int pre_delete_cryptcompress(struct inode *inode)
+{
+	return cryptcompress_truncate(inode, 0, 0);
+}
+
 /* plugin->u.file.setattr method
    see plugin.h for description */
 int setattr_cryptcompress(struct dentry *dentry,	/* Object to change attributes */
diff -puN fs/reiser4/plugin/file/file.c~reiser4-add-put_inode fs/reiser4/plugin/file/file.c
--- linux-2.6.13/fs/reiser4/plugin/file/file.c~reiser4-add-put_inode	2005-10-03 16:00:08.000000000 +0400
+++ linux-2.6.13-vs/fs/reiser4/plugin/file/file.c	2005-10-03 17:10:02.000000000 +0400
@@ -721,31 +721,25 @@ append_hole(hint_t * hint, struct inode 
 	return result;
 }
 
-/**
- * truncate_file_body - change length of file
- * @inode: inode of file
- * @new_size: new file length
- *
- * Adjusts items file @inode is built of to match @new_size. It may either cut
- * items or add them to represent a hole at the end of file. The caller has to
- * obtain exclusive access to the file.
- */
+/* this either cuts or add items of/to the file so that items match
+   new_size. It is used in unix_file_setattr when it is used to truncate
+   VS-FIXME-HANS: explain that and in unix_file_delete */
 static int truncate_file_body(struct inode *inode, loff_t new_size)
 {
 	int result;
+	hint_t *hint;
 
-	if (inode->i_size < new_size) {
-		hint_t *hint;
-
-		hint = kmalloc(sizeof(*hint), GFP_KERNEL);
-		if (hint == NULL)
-			return RETERR(-ENOMEM);
-		hint_init_zero(hint);
-		result = append_hole(hint, inode, new_size,
-				     1 /* exclusive access is obtained */ );
-		kfree(hint);
-	} else
+	hint = kmalloc(sizeof(*hint), GFP_KERNEL);
+	if (hint == NULL)
+		return RETERR(-ENOMEM);
+	hint_init_zero(hint);
+	if (inode->i_size < new_size)
+		result =
+		    append_hole(hint, inode, new_size,
+				1 /* exclusive access is obtained */ );
+	else
 		result = shorten_file(inode, new_size);
+	kfree(hint);
 	return result;
 }
 
@@ -2965,10 +2959,43 @@ init_inode_data_unix_file(struct inode *
 }
 
 /**
+ * pre_delete_unix_file - pre_delete of file_plugin
+ * @inode: inode to delete body of
+ * 
+ * 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
+ */
+int pre_delete_unix_file(struct inode *inode)
+{
+	unix_file_info_t *uf_info;
+	int result;
+
+	txn_restart_current();
+
+	uf_info = unix_file_inode_data(inode);
+	get_exclusive_access(uf_info);
+	result = truncate_file_body(inode, 0/* size */);
+	drop_exclusive_access(uf_info);
+	return result;}
+
+/**
  * delete_object_unix_file - delete_object of file_plugin
  * @inode: inode to be deleted
  *
- * Truncates file to length 0, removes stat data and safe link.
+ * removes stat data and safe link.
  */
 int delete_object_unix_file(struct inode *inode)
 {
@@ -2981,16 +3008,6 @@ int delete_object_unix_file(struct inode
 	if (inode_get_flag(inode, REISER4_NO_SD))
 		return 0;
 
-	/* truncate file bogy first */
-	uf_info = unix_file_inode_data(inode);
-	get_exclusive_access(uf_info);
-	result = truncate_file_body(inode, 0 /* size */ );
-	drop_exclusive_access(uf_info);
-
-	if (result)
-		warning("", "failed to truncate file (%llu) on removal: %d",
-			get_inode_oid(inode), result);
-
 	/* remove stat data and safe link */
 	return delete_object_common(inode);
 }
diff -puN fs/reiser4/plugin/file/file.h~reiser4-add-put_inode fs/reiser4/plugin/file/file.h
--- linux-2.6.13/fs/reiser4/plugin/file/file.h~reiser4-add-put_inode	2005-10-03 16:00:10.000000000 +0400
+++ linux-2.6.13-vs/fs/reiser4/plugin/file/file.h	2005-10-03 16:02:00.000000000 +0400
@@ -40,7 +40,7 @@ int flow_by_inode_unix_file(struct inode
 int owns_item_unix_file(const struct inode *, const coord_t *);
 void init_inode_data_unix_file(struct inode *, reiser4_object_create_data *,
 			       int create);
-int delete_object_unix_file(struct inode *);
+int pre_delete_unix_file(struct inode *);
 
 /* all the write into unix file is performed by item write method. Write method
    of unix file plugin only decides which item plugin (extent or tail) and in
@@ -193,6 +193,7 @@ int cut_tree_worker_cryptcompress(tap_t 
 				  reiser4_key * smallest_removed,
 				  struct inode *object, int truncate,
 				  int *progress);
+int pre_delete_cryptcompress(struct inode *);
 void destroy_inode_cryptcompress(struct inode *);
 
 extern reiser4_plugin_ops cryptcompress_plugin_ops;
diff -puN fs/reiser4/plugin/file_plugin_common.c~reiser4-add-put_inode fs/reiser4/plugin/file_plugin_common.c
--- linux-2.6.13/fs/reiser4/plugin/file_plugin_common.c~reiser4-add-put_inode	2005-10-03 16:00:34.000000000 +0400
+++ linux-2.6.13-vs/fs/reiser4/plugin/file_plugin_common.c	2005-10-03 16:02:00.000000000 +0400
@@ -164,14 +164,9 @@ create_object_common(struct inode *objec
 
 static int common_object_delete_no_reserve(struct inode *inode);
 
-/**
- * delete_object_common - delete_object of file_plugin
- * @inode: inode to be deleted
- *
- * This is common implementation of delete_object method of file_plugin. It
- * applies to object its deletion consists of removing two items - stat data
- * and safe-link.
- */
+/* this is common implementation of delete method of file plugin
+   all it does is object stat data removal
+*/
 int delete_object_common(struct inode *inode)
 {
 	int result;
@@ -182,7 +177,6 @@ int delete_object_common(struct inode *i
 	assert("nikita-3420", inode->i_size == 0 || S_ISLNK(inode->i_mode));
 	assert("nikita-3421", inode->i_nlink == 0);
 
-
 	if (!inode_get_flag(inode, REISER4_NO_SD)) {
 		reiser4_block_nr reserve;
 
diff -puN fs/reiser4/plugin/object.c~reiser4-add-put_inode fs/reiser4/plugin/object.c
--- linux-2.6.13/fs/reiser4/plugin/object.c~reiser4-add-put_inode	2005-10-03 16:00:38.000000000 +0400
+++ linux-2.6.13-vs/fs/reiser4/plugin/object.c	2005-10-03 16:02:00.000000000 +0400
@@ -126,7 +126,7 @@ file_plugin file_plugins[LAST_FILE_PLUGI
 		.set_plug_in_inode = set_plug_in_inode_common,
 		.adjust_to_parent = adjust_to_parent_common,
 		.create_object = create_object_common,	/* this is not inode_operations's create */
-		.delete_object = delete_object_unix_file,
+		.delete_object = delete_object_common,
 		.add_link = add_link_common,
 		.rem_link = rem_link_common,
 		.owns_item = owns_item_unix_file,
@@ -141,6 +141,7 @@ file_plugin file_plugins[LAST_FILE_PLUGI
 		},
 		.init_inode_data = init_inode_data_unix_file,
 		.cut_tree_worker = cut_tree_worker_common,
+		.pre_delete = pre_delete_unix_file,
 		.wire = {
 			.write = wire_write_common,
 			.read = wire_read_common,
@@ -338,6 +339,7 @@ file_plugin file_plugins[LAST_FILE_PLUGI
 		},
 		.init_inode_data = init_inode_data_cryptcompress,
 		.cut_tree_worker = cut_tree_worker_cryptcompress,
+		.pre_delete = pre_delete_cryptcompress,
 		.destroy_inode = destroy_inode_cryptcompress,
 		.wire = {
 			.write = wire_write_common,
diff -puN fs/reiser4/plugin/plugin.h~reiser4-add-put_inode fs/reiser4/plugin/plugin.h
--- linux-2.6.13/fs/reiser4/plugin/plugin.h~reiser4-add-put_inode	2005-10-03 16:00:43.000000000 +0400
+++ linux-2.6.13-vs/fs/reiser4/plugin/plugin.h	2005-10-03 16:02:00.000000000 +0400
@@ -249,10 +249,10 @@ typedef struct file_plugin {
 			      reiser4_object_create_data *);
 
 	/*
-	 * this method should check REISER4_NO_SD and set REISER4_NO_SD on
-	 * success. Deletion of an object usually includes removal of items
-	 * building file body (for directories this is removal of "." and "..")
-	 * and removal of stat-data item.
+	 * delete empty object. This method should check REISER4_NO_SD and set
+	 * REISER4_NO_SD on success. Deletion of empty object at least includes
+	 * removal of stat-data if any. For directories this also includes
+	 * removal of dot and dot-dot.
 	 */
 	int (*delete_object) (struct inode *);
 
@@ -324,6 +324,9 @@ typedef struct file_plugin {
 				reiser4_key * smallest_removed, struct inode *,
 				int, int *);
 
+	/* truncate file to zero size. called by reiser4_drop_inode before truncate_inode_pages */
+	int (*pre_delete) (struct inode *);
+
 	/* called from ->destroy_inode() */
 	void (*destroy_inode) (struct inode *);
 
diff -puN fs/reiser4/super.c~reiser4-add-put_inode fs/reiser4/super.c
--- linux-2.6.13/fs/reiser4/super.c~reiser4-add-put_inode	2005-10-03 16:00:52.000000000 +0400
+++ linux-2.6.13-vs/fs/reiser4/super.c	2005-10-03 16:02:00.000000000 +0400
@@ -17,6 +17,7 @@
 #include <linux/types.h>	/* for __u??  */
 #include <linux/fs.h>		/* for struct super_block  */
 
+							/*const __u32 REISER4_SUPER_MAGIC = 0x52345362;*//* (*(__u32 *)"R4Sb"); */
 
 static __u64 reserved_for_gid(const struct super_block *super, gid_t gid);
 static __u64 reserved_for_uid(const struct super_block *super, uid_t uid);
diff -puN fs/reiser4/vfs_ops.c~reiser4-add-put_inode fs/reiser4/vfs_ops.c
diff -puN fs/reiser4/super_ops.c~reiser4-add-put_inode fs/reiser4/super_ops.c
--- linux-2.6.13/fs/reiser4/super_ops.c~reiser4-add-put_inode	2005-10-03 16:39:16.000000000 +0400
+++ linux-2.6.13-vs/fs/reiser4/super_ops.c	2005-10-03 17:13:57.000000000 +0400
@@ -156,6 +156,36 @@ static void reiser4_destroy_inode(struct
 }
 
 /**
+ * reiser4_put_inode - put_inode of super_operations
+ * @inode: inode being removed from cache
+ *
+ * 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_put_inode(struct inode *inode)
+{
+	reiser4_context *ctx;
+	file_plugin *fplug;
+
+	fplug = inode_file_plugin(inode);
+	if (fplug == NULL ||
+	    inode->i_nlink != 0 ||
+	    atomic_read(&inode->i_count) > 1 || fplug->pre_delete == NULL)
+		return;
+
+	ctx = init_context(inode->i_sb);
+	if (IS_ERR(ctx)) {
+		warning("vs-14", "failed to init context");
+		return;
+	}
+	/* 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);
+}
+
+/**
  * reiser4_dirty_inode - dirty_inode of super operations
  * @inode: inode being dirtied
  *
@@ -443,6 +473,7 @@ static int reiser4_show_options(struct s
 struct super_operations reiser4_super_operations = {
 	.alloc_inode = reiser4_alloc_inode,
 	.destroy_inode = reiser4_destroy_inode,
+	.put_inode = reiser4_put_inode,
 	.dirty_inode = reiser4_dirty_inode,
 	.delete_inode = reiser4_delete_inode,
 	.put_super = reiser4_put_super,

_
