Placeholder pages allow DIO to use locking rules similar to that of
writepage.  DIO can now fill holes, and it can extend the file via
get_block().

i_mutex can be dropped during writes if we are writing inside i_size.

Signed-off-by: Chris Mason <[EMAIL PROTECTED]>

diff -r 317779b11fe1 -r ac51e7a4c7a6 fs/direct-io.c
--- a/fs/direct-io.c    Thu Dec 21 15:31:30 2006 -0500
+++ b/fs/direct-io.c    Thu Dec 21 15:31:30 2006 -0500
@@ -70,6 +70,7 @@ struct dio {
        int rw;
        loff_t i_size;                  /* i_size when submitted */
        int lock_type;                  /* doesn't change */
+       int reacquire_i_mutex;          /* should we get i_mutex when done? */
        unsigned blkbits;               /* doesn't change */
        unsigned blkfactor;             /* When we're using an alignment which
                                           is finer than the filesystem's soft
@@ -218,8 +219,7 @@ static int lock_page_range(struct dio *d
                return 0;
        return find_or_insert_placeholders(mapping, dio->tmppages, start, end,
                                          ARRAY_SIZE(dio->tmppages),
-                                         GFP_KERNEL,
-                                         dio->rw == READ);
+                                         GFP_KERNEL, 1);
 }
 
 
@@ -282,6 +282,8 @@ static int dio_complete(struct dio *dio,
        unlock_page_range(dio, dio->fspages_start_off,
                          dio->fspages_end_off - dio->fspages_start_off);
        dio->fspages_end_off = dio->fspages_start_off;
+       if (dio->reacquire_i_mutex)
+               mutex_lock(&dio->inode->i_mutex);
 
        if (ret == 0)
                ret = dio->page_errors;
@@ -568,13 +570,8 @@ static int get_more_blocks(struct dio *d
                map_bh->b_size = fs_count << dio->inode->i_blkbits;
 
                create = dio->rw & WRITE;
-               if (dio->lock_type == DIO_LOCKING) {
-                       if (dio->block_in_file < (i_size_read(dio->inode) >>
-                                                       dio->blkbits))
-                               create = 0;
-               } else if (dio->lock_type == DIO_NO_LOCKING) {
+               if (dio->lock_type == DIO_NO_LOCKING)
                        create = 0;
-               }
                index = fs_startblk >> (PAGE_CACHE_SHIFT -
                                        dio->inode->i_blkbits);
                end = (dio->final_block_in_request >> dio->blkfactor) >>
@@ -1258,6 +1255,13 @@ __blockdev_direct_IO(int rw, struct kioc
        dio->is_async = !is_sync_kiocb(iocb) && !((rw & WRITE) &&
                (end > i_size_read(inode)));
 
+       /* if our write is inside i_size, we can drop i_mutex */
+       dio->reacquire_i_mutex = 0;
+       if ((rw & WRITE) && dio_lock_type == DIO_LOCKING &&
+          end <= i_size_read(inode) && is_sync_kiocb(iocb)) {
+               dio->reacquire_i_mutex = 1;
+               mutex_unlock(&inode->i_mutex);
+       }
        retval = direct_io_worker(rw, iocb, inode, iov, offset,
                                nr_segs, blkbits, get_block, end_io, dio);
 out:
diff -r 317779b11fe1 -r ac51e7a4c7a6 mm/filemap.c
--- a/mm/filemap.c      Thu Dec 21 15:31:30 2006 -0500
+++ b/mm/filemap.c      Thu Dec 21 15:31:30 2006 -0500
@@ -2865,10 +2865,19 @@ generic_file_direct_IO(int rw, struct ki
        retval = mapping->a_ops->direct_IO(rw, iocb, iov,
                                        offset, nr_segs);
        if (rw == WRITE && mapping->nrpages) {
+               int err;
                pgoff_t end = (offset + write_len - 1)
                                        >> PAGE_CACHE_SHIFT;
-               int err = invalidate_inode_pages2_range(mapping,
-                               offset >> PAGE_CACHE_SHIFT, end);
+
+               /* O_DIRECT is allowed to drop i_mutex, so more data
+                * could have been dirtied by others.  Start io one more
+                * time
+                */
+               err = filemap_fdatawrite_range(mapping, offset,
+                                              offset + write_len - 1);
+               if (!err)
+                       err = invalidate_inode_pages2_range(mapping,
+                                       offset >> PAGE_CACHE_SHIFT, end);
                if (err)
                        retval = err;
        }


-
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to