]> git.neil.brown.name Git - LaFS.git/commitdiff
wait more effectively for truncate to progress.
authorNeilBrown <neilb@suse.de>
Sun, 1 Aug 2010 00:57:01 +0000 (10:57 +1000)
committerNeilBrown <neilb@suse.de>
Mon, 9 Aug 2010 02:01:42 +0000 (12:01 +1000)
The times that we wait for truncate to progress, we hold
i_mutex, so truncate cannot progress.
So if there is a need to wait, we need to call the orphan
handler directly.

Signed-off-by: NeilBrown <neilb@suse.de>
file.c
inode.c

diff --git a/file.c b/file.c
index 9c940a19cdf250e9c358434dd0c8d3d0fbec4c0e..437be731c4117870e1ae8cfdb13fba7b49424557 100644 (file)
--- a/file.c
+++ b/file.c
@@ -137,6 +137,7 @@ lafs_write_begin(struct file *file, struct address_space *mapping,
        pgoff_t index;
        unsigned from, to;
        struct page *page;
+       DEFINE_WAIT(wq);
 
        index = pos >> PAGE_CACHE_SHIFT;
        from = pos & (PAGE_CACHE_SIZE - 1);
@@ -145,9 +146,18 @@ lafs_write_begin(struct file *file, struct address_space *mapping,
        first = from >> bits;
        last = (to-1) >> bits;
 
-       wait_event(fs->trunc_wait,
-                  !test_bit(I_Trunc, &LAFSI(ino)->iflags) ||
-                  LAFSI(ino)->trunc_next > last);
+       while (test_bit(I_Trunc, &LAFSI(ino)->iflags) &&
+              LAFSI(ino)->trunc_next <= last) {
+               struct datablock *db = lafs_inode_dblock(ino,
+                                                        SYNC, MKREF(writetrunc));
+               prepare_to_wait(&fs->async_complete, &wq,
+                               TASK_UNINTERRUPTIBLE);
+               lafs_inode_handle_orphan(db);
+               if (test_bit(B_Orphan, &db->b.flags))
+                       schedule();
+               putdref(db, MKREF(writetrunc));
+       }
+       finish_wait(&fs->async_complete, &wq);
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29)
        page = __grab_cache_page(mapping, index);
diff --git a/inode.c b/inode.c
index 52f5d995c9a9f9938902bd9e3d2ef519a0877399..9ca882e9aa1180f99487683cd75040748e0c2e18 100644 (file)
--- a/inode.c
+++ b/inode.c
@@ -1591,20 +1591,31 @@ void lafs_truncate(struct inode *ino)
         */
        struct fs *fs = fs_from_inode(ino);
        struct datablock *db = lafs_inode_dblock(ino, SYNC, MKREF(trunc));
+       loff_t trunc_block;
+       DEFINE_WAIT(wq);
 
        if (IS_ERR(db))
                return;
 
-       wait_event(fs->trunc_wait,
-                  !test_bit(I_Trunc, &LAFSI(ino)->iflags));
+       trunc_block = ((i_size_read(ino) + fs->blocksize - 1)
+                      >> fs->blocksize_bits);
+       /* We hold i_mutex, so regular orphan processing cannot
+        * contine - we have to push it forward ourselves.
+        */
+       while (test_bit(I_Trunc, &LAFSI(ino)->iflags) &&
+              LAFSI(ino)->trunc_next < trunc_block) {
+               prepare_to_wait(&fs->async_complete, &wq,
+                               TASK_UNINTERRUPTIBLE);
+               lafs_inode_handle_orphan(db);
+               if (test_bit(B_Orphan, &db->b.flags))
+                       schedule();
+       }
+       finish_wait(&fs->async_complete, &wq);
 
        /* FIXME there is nothing I can do with an error here */
        lafs_make_orphan(fs, db);
 
-       LAFSI(ino)->trunc_next = (i_size_read(ino) +
-                                 fs->blocksize - 1)
-               >> fs->blocksize_bits;
-       set_bit(I_Trunc, &LAFSI(ino)->iflags);
+       LAFSI(ino)->trunc_next = trunc_block;
        putdref(db, MKREF(trunc));
 }