From: NeilBrown Date: Sun, 1 Aug 2010 00:57:01 +0000 (+1000) Subject: wait more effectively for truncate to progress. X-Git-Url: http://git.neil.brown.name/?a=commitdiff_plain;h=8c394fff184ed83cbc4ac3c48c99440fdc7d4b02;p=LaFS.git wait more effectively for truncate to progress. 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 --- diff --git a/file.c b/file.c index 9c940a1..437be73 100644 --- 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 52f5d99..9ca882e 100644 --- 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)); }