diff options
-rw-r--r-- | fs/gfs2/aops.c | 30 |
1 files changed, 30 insertions, 0 deletions
diff --git a/fs/gfs2/aops.c b/fs/gfs2/aops.c index 0bad69ed6336..76251600cbea 100644 --- a/fs/gfs2/aops.c +++ b/fs/gfs2/aops.c | |||
@@ -999,6 +999,7 @@ static ssize_t gfs2_direct_IO(int rw, struct kiocb *iocb, | |||
999 | { | 999 | { |
1000 | struct file *file = iocb->ki_filp; | 1000 | struct file *file = iocb->ki_filp; |
1001 | struct inode *inode = file->f_mapping->host; | 1001 | struct inode *inode = file->f_mapping->host; |
1002 | struct address_space *mapping = inode->i_mapping; | ||
1002 | struct gfs2_inode *ip = GFS2_I(inode); | 1003 | struct gfs2_inode *ip = GFS2_I(inode); |
1003 | struct gfs2_holder gh; | 1004 | struct gfs2_holder gh; |
1004 | int rv; | 1005 | int rv; |
@@ -1019,6 +1020,35 @@ static ssize_t gfs2_direct_IO(int rw, struct kiocb *iocb, | |||
1019 | if (rv != 1) | 1020 | if (rv != 1) |
1020 | goto out; /* dio not valid, fall back to buffered i/o */ | 1021 | goto out; /* dio not valid, fall back to buffered i/o */ |
1021 | 1022 | ||
1023 | /* | ||
1024 | * Now since we are holding a deferred (CW) lock at this point, you | ||
1025 | * might be wondering why this is ever needed. There is a case however | ||
1026 | * where we've granted a deferred local lock against a cached exclusive | ||
1027 | * glock. That is ok provided all granted local locks are deferred, but | ||
1028 | * it also means that it is possible to encounter pages which are | ||
1029 | * cached and possibly also mapped. So here we check for that and sort | ||
1030 | * them out ahead of the dio. The glock state machine will take care of | ||
1031 | * everything else. | ||
1032 | * | ||
1033 | * If in fact the cached glock state (gl->gl_state) is deferred (CW) in | ||
1034 | * the first place, mapping->nr_pages will always be zero. | ||
1035 | */ | ||
1036 | if (mapping->nrpages) { | ||
1037 | loff_t lstart = offset & (PAGE_CACHE_SIZE - 1); | ||
1038 | loff_t len = iov_length(iov, nr_segs); | ||
1039 | loff_t end = PAGE_ALIGN(offset + len) - 1; | ||
1040 | |||
1041 | rv = 0; | ||
1042 | if (len == 0) | ||
1043 | goto out; | ||
1044 | if (test_and_clear_bit(GIF_SW_PAGED, &ip->i_flags)) | ||
1045 | unmap_shared_mapping_range(ip->i_inode.i_mapping, offset, len); | ||
1046 | rv = filemap_write_and_wait_range(mapping, lstart, end); | ||
1047 | if (rv) | ||
1048 | return rv; | ||
1049 | truncate_inode_pages_range(mapping, lstart, end); | ||
1050 | } | ||
1051 | |||
1022 | rv = __blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, | 1052 | rv = __blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, |
1023 | offset, nr_segs, gfs2_get_block_direct, | 1053 | offset, nr_segs, gfs2_get_block_direct, |
1024 | NULL, NULL, 0); | 1054 | NULL, NULL, 0); |