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"

_