 fs/reiser4/plugin/file/file.c            |   53 ++++++++++++-------------------
 fs/reiser4/plugin/file/file.h            |    4 ++
 fs/reiser4/plugin/file/tail_conversion.c |   13 +++++++
 fs/reiser4/plugin/item/extent_file_ops.c |   19 +++++++++++
 fs/reiser4/plugin/item/tail.c            |   12 +++++++
 5 files changed, 69 insertions(+), 32 deletions(-)

diff -puN fs/reiser4/plugin/file/file.c~reiser4-tmp4 fs/reiser4/plugin/file/file.c
--- linux-2.6.12-rc2-mm3/fs/reiser4/plugin/file/file.c~reiser4-tmp4	2005-04-26 12:53:10.678341230 +0400
+++ linux-2.6.12-rc2-mm3-vs/fs/reiser4/plugin/file/file.c	2005-04-27 17:35:17.341020658 +0400
@@ -1347,6 +1347,9 @@ capture_unix_file(struct inode *inode, s
 		 * this function is out of reiser4 context and may safely
 		 * sleep on semaphore.
 		 */
+		assert("", LOCK_CNT_NIL(inode_sem_w));
+		assert("", LOCK_CNT_NIL(inode_sem_r));
+#if 0
 		if (is_in_reiser4_context()) {
 			if (down_read_trylock(&uf_info->latch) == 0) {
 /* ZAM-FIXME-HANS: please explain this error handling here, grep for
@@ -1354,6 +1357,7 @@ capture_unix_file(struct inode *inode, s
  * represent busy loops that we should recode.  Also tell me whether
  * any of them fail to return EBUSY to user space, and if yes, then
  * recode them to not use the EBUSY macro.*/
+				warning("", "does this ever happen?");
 				result = RETERR(-EBUSY);
 				reiser4_exit_context(&ctx);
 				break;
@@ -1361,7 +1365,9 @@ capture_unix_file(struct inode *inode, s
 		} else
 			down_read(&uf_info->latch);
 		LOCK_CNT_INC(inode_sem_r);
-
+#endif
+		txn_restart_current();
+		get_nonexclusive_access(uf_info, 0);
 		while (to_capture > 0) {
 			pgoff_t start;
 
@@ -1396,8 +1402,11 @@ capture_unix_file(struct inode *inode, s
 			/* there may be left more pages */
 			redirty_inode(inode);
 
+		drop_nonexclusive_access(uf_info);
+/*
 		up_read(&uf_info->latch);
 		LOCK_CNT_DEC(inode_sem_r);
+*/
 		if (result < 0) {
 			/* error happened */
 			reiser4_exit_context(&ctx);
@@ -1637,7 +1646,7 @@ reiser4_put_user_pages(struct page **pag
 
 /* this is called with nonexclusive access obtained, file's container can not change */
 static size_t
-read_file(hint_t *hint, file_container_t container,
+read_file(hint_t *hint,
 	  struct file *file, /* file to write to */
 	  char *buf, /* address of user-space buffer */
 	  size_t count, /* number of bytes to write */
@@ -1652,33 +1661,6 @@ read_file(hint_t *hint, file_container_t
 
 	inode = file->f_dentry->d_inode;
 
-	/* we have nonexclusive access (NA) obtained. File's container may not
-	   change until we drop NA. If possible - calculate read function
-	   beforehand */
-	switch(container) {
-	case UF_CONTAINER_EXTENTS:
-		read_f = item_plugin_by_id(EXTENT_POINTER_ID)->s.file.read;
-		break;
-
-	case UF_CONTAINER_TAILS:
-		/* this is read-ahead for tails-only files */
-		result = reiser4_file_readahead(file, *off, count);
-		if (result)
-			return result;
-
-		read_f = item_plugin_by_id(FORMATTING_ID)->s.file.read;
-		break;
-
-	case UF_CONTAINER_UNKNOWN:
-		read_f = 0;
-		break;
-
-	case UF_CONTAINER_EMPTY:
-	default:
-		warning("vs-1297", "File (ino %llu) has unexpected state: %d\n",
-			(unsigned long long)get_inode_oid(inode), container);
-		return RETERR(-EIO);
-	}
 
 	/* build flow */
 	assert("vs-1250", inode_file_plugin(inode)->flow_by_inode == flow_by_inode_unix_file);
@@ -1710,9 +1692,9 @@ read_file(hint_t *hint, file_container_t
 		if (hint->ext_coord.valid == 0)
 			validate_extended_coord(&hint->ext_coord, get_key_offset(&flow.key));
 
+		assert("vs-4", hint->ext_coord.valid == 1);
 		/* call item's read method */
-		if (!read_f)
-			read_f = item_plugin_by_coord(coord)->s.file.read;
+		read_f = item_plugin_by_coord(coord)->s.file.read;
 		result = read_f(file, &flow, hint);
 		zrelse(loaded);
 		done_lh(hint->ext_coord.lh);
@@ -1813,7 +1795,7 @@ read_unix_file(struct file *file, char *
 			to_read = inode->i_size - *off;
 
 		assert("vs-1706", to_read <= left);
-		read = read_file(&hint, uf_info->container, file, buf, to_read, off);
+		read = read_file(&hint, file, buf, to_read, off);
 
 		if (user_space)
 			reiser4_put_user_pages(pages, nr_pages);
@@ -2065,6 +2047,7 @@ mmap_unix_file(struct file *file, struct
 	inode = file->f_dentry->d_inode;
 	uf_info = unix_file_inode_data(inode);
 
+  	down(&uf_info->write);
 	get_exclusive_access(uf_info);
 
 	if (!IS_RDONLY(inode) && (vma->vm_flags & (VM_MAYWRITE | VM_SHARED))) {
@@ -2073,12 +2056,14 @@ mmap_unix_file(struct file *file, struct
 		result = finish_conversion(inode);
 		if (result) {
 			drop_exclusive_access(uf_info);
+			up(&uf_info->write);
 			return result;
 		}
 
 		result = find_file_state(uf_info);
 		if (result != 0) {
 			drop_exclusive_access(uf_info);
+			up(&uf_info->write);
 			return result;
 		}
 
@@ -2090,6 +2075,7 @@ mmap_unix_file(struct file *file, struct
 			result = check_pages_unix_file(inode);
 			if (result) {
 				drop_exclusive_access(uf_info);
+				up(&uf_info->write);
 				return result;
 			}
 		}
@@ -2103,6 +2089,7 @@ mmap_unix_file(struct file *file, struct
 	}
 
 	drop_exclusive_access(uf_info);
+	up(&uf_info->write);
 	return result;
 }
 
@@ -2323,6 +2310,7 @@ release_unix_file(struct inode *object, 
 	uf_info = unix_file_inode_data(object);
 	result = 0;
 
+  	down(&uf_info->write);
 	get_exclusive_access(uf_info);
 	if (atomic_read(&file->f_dentry->d_count) == 1 &&
 	    uf_info->container == UF_CONTAINER_EXTENTS &&
@@ -2335,6 +2323,7 @@ release_unix_file(struct inode *object, 
 		}
 	}
 	drop_exclusive_access(uf_info);
+	up(&uf_info->write);
 	return 0;
 }
 
diff -puN fs/reiser4/plugin/file/tail_conversion.c~reiser4-tmp4 fs/reiser4/plugin/file/tail_conversion.c
--- linux-2.6.12-rc2-mm3/fs/reiser4/plugin/file/tail_conversion.c~reiser4-tmp4	2005-04-26 12:53:10.684340491 +0400
+++ linux-2.6.12-rc2-mm3-vs/fs/reiser4/plugin/file/tail_conversion.c	2005-04-26 12:53:10.741333466 +0400
@@ -32,6 +32,7 @@ get_exclusive_access(unix_file_info_t *u
 	BUG_ON(get_current_context()->trans->atom != NULL);
 	LOCK_CNT_INC(inode_sem_w);
 	down_write(&uf_info->latch);
+	uf_info->exclusive_use = 1;
 	assert("vs-1713", uf_info->ea_owner == NULL);
 	assert("vs-1713", atomic_read(&uf_info->nr_neas) == 0);
 	ON_DEBUG(uf_info->ea_owner = current);
@@ -43,6 +44,7 @@ drop_exclusive_access(unix_file_info_t *
 	assert("vs-1714", uf_info->ea_owner == current);
 	assert("vs-1715", atomic_read(&uf_info->nr_neas) == 0);
 	ON_DEBUG(uf_info->ea_owner = NULL);
+	uf_info->exclusive_use = 0;
 	up_write(&uf_info->latch);
 	assert("nikita-3049", LOCK_CNT_NIL(inode_sem_r));
 	assert("nikita-3049", LOCK_CNT_GTZ(inode_sem_w));
@@ -408,8 +410,19 @@ tail2extent(unix_file_info_t *uf_info)
 			release_all_pages(pages, sizeof_array(pages));
 			if (result)
 				goto error;
+			/* we have to drop exclusive access to avoid deadlock
+			 * which may happen because called by
+			 * reiser4_writepages capture_unix_file requires to get
+			 * non-exclusive access to a file. It is safe to drop
+			 * EA in the middle of tail2extent conversion because
+			 * write_unix_file/unix_setattr(truncate)/release_unix_file(extent2tail)
+			 * are serialized by uf_info->write semaphore and
+			 * because read_unix_file works (should at least) on
+			 * partially converted files */
+			drop_exclusive_access(uf_info);
 			/* throttle the conversion */
 			reiser4_throttle_write(inode);
+			get_exclusive_access(uf_info);
 		}
 	}
 
diff -puN fs/reiser4/plugin/item/extent_file_ops.c~reiser4-tmp4 fs/reiser4/plugin/item/extent_file_ops.c
--- linux-2.6.12-rc2-mm3/fs/reiser4/plugin/item/extent_file_ops.c~reiser4-tmp4	2005-04-26 12:53:10.698338766 +0400
+++ linux-2.6.12-rc2-mm3-vs/fs/reiser4/plugin/item/extent_file_ops.c	2005-04-27 15:00:43.844088338 +0400
@@ -644,6 +644,8 @@ extent_balance_dirty_pages(struct inode 
 			   hint_t *hint)
 {
 	int result;
+	int excl;
+	unix_file_info_t *uf_info;
 
 	if (hint->ext_coord.valid)
 		set_hint(hint, &f->key, ZNODE_WRITE_LOCK);
@@ -666,7 +668,17 @@ extent_balance_dirty_pages(struct inode 
 			return result;
 	}
 
+	uf_info = unix_file_inode_data(inode);
+	excl = unix_file_inode_data(inode)->exclusive_use;
+	if (excl)
+		drop_exclusive_access(uf_info);
+	else
+		drop_nonexclusive_access(uf_info);
 	reiser4_throttle_write(inode);
+	if (excl)
+		get_exclusive_access(uf_info);
+	else
+		get_nonexclusive_access(uf_info, 0);
 	return 0;
 }
 
@@ -1197,6 +1209,13 @@ extent_readpage_filler(void *data, struc
 		lock_page(page);
 		return RETERR(-EIO);
 	}
+	if (!item_is_extent(&ext_coord->coord)) {
+		/* tail conversion is running in parallel */
+		unset_hint(hint);
+		done_lh(ext_coord->lh);
+		lock_page(page);
+		return RETERR(-EIO);
+	}
 
 	if (ext_coord->valid == 0)
 		init_coord_extension_extent(ext_coord, offset);
diff -puN fs/reiser4/plugin/item/tail.c~reiser4-tmp4 fs/reiser4/plugin/item/tail.c
--- linux-2.6.12-rc2-mm3/fs/reiser4/plugin/item/tail.c~reiser4-tmp4	2005-04-26 12:53:10.709337410 +0400
+++ linux-2.6.12-rc2-mm3-vs/fs/reiser4/plugin/item/tail.c	2005-04-26 12:53:10.745332973 +0400
@@ -454,6 +454,8 @@ tail_balance_dirty_pages(struct address_
 {
 	int result;
 	struct inode *inode;
+	int excl;
+	unix_file_info_t *uf_info;
 
 	if (hint->ext_coord.valid)
 		set_hint(hint, &f->key, ZNODE_WRITE_LOCK);
@@ -480,7 +482,17 @@ tail_balance_dirty_pages(struct address_
 	   files which are built of tails */
 	move_inode_out_from_sync_inodes_loop(mapping);
 
+	uf_info = unix_file_inode_data(inode);
+	excl = unix_file_inode_data(inode)->exclusive_use;
+	if (excl)
+		drop_exclusive_access(uf_info);
+	else
+		drop_nonexclusive_access(uf_info);
 	reiser4_throttle_write(inode);
+	if (excl)
+		get_exclusive_access(uf_info);
+	else
+		get_nonexclusive_access(uf_info, 0);
 	return 0;
 }
 
diff -puN fs/reiser4/plugin/file/file.h~reiser4-tmp4 fs/reiser4/plugin/file/file.h
--- linux-2.6.12-rc2-mm3/fs/reiser4/plugin/file/file.h~reiser4-tmp4	2005-04-26 12:53:10.714336794 +0400
+++ linux-2.6.12-rc2-mm3-vs/fs/reiser4/plugin/file/file.h	2005-04-26 12:53:10.746332850 +0400
@@ -85,6 +85,10 @@ typedef struct unix_file_info {
 } unix_file_info_t;
 
 struct unix_file_info *unix_file_inode_data(const struct inode * inode);
+void get_exclusive_access(unix_file_info_t *);
+void drop_exclusive_access(unix_file_info_t *);
+void get_nonexclusive_access(unix_file_info_t *, int);
+void drop_nonexclusive_access(unix_file_info_t *);
 
 #include "../item/extent.h"
 #include "../item/tail.h"

_
