diff options
Diffstat (limited to 'mm/filemap.c')
-rw-r--r-- | mm/filemap.c | 55 |
1 files changed, 47 insertions, 8 deletions
diff --git a/mm/filemap.c b/mm/filemap.c index 7c7addb9333c..cb26e33fd0ff 100644 --- a/mm/filemap.c +++ b/mm/filemap.c | |||
@@ -75,8 +75,8 @@ generic_file_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, | |||
75 | * ->mmap_sem | 75 | * ->mmap_sem |
76 | * ->lock_page (access_process_vm) | 76 | * ->lock_page (access_process_vm) |
77 | * | 77 | * |
78 | * ->mmap_sem | 78 | * ->i_mutex (generic_file_buffered_write) |
79 | * ->i_mutex (msync) | 79 | * ->mmap_sem (fault_in_pages_readable->do_page_fault) |
80 | * | 80 | * |
81 | * ->i_mutex | 81 | * ->i_mutex |
82 | * ->i_alloc_sem (various) | 82 | * ->i_alloc_sem (various) |
@@ -2236,7 +2236,7 @@ __generic_file_aio_write_nolock(struct kiocb *iocb, const struct iovec *iov, | |||
2236 | unsigned long nr_segs, loff_t *ppos) | 2236 | unsigned long nr_segs, loff_t *ppos) |
2237 | { | 2237 | { |
2238 | struct file *file = iocb->ki_filp; | 2238 | struct file *file = iocb->ki_filp; |
2239 | const struct address_space * mapping = file->f_mapping; | 2239 | struct address_space * mapping = file->f_mapping; |
2240 | size_t ocount; /* original count */ | 2240 | size_t ocount; /* original count */ |
2241 | size_t count; /* after file limit checks */ | 2241 | size_t count; /* after file limit checks */ |
2242 | struct inode *inode = mapping->host; | 2242 | struct inode *inode = mapping->host; |
@@ -2289,8 +2289,11 @@ __generic_file_aio_write_nolock(struct kiocb *iocb, const struct iovec *iov, | |||
2289 | 2289 | ||
2290 | /* coalesce the iovecs and go direct-to-BIO for O_DIRECT */ | 2290 | /* coalesce the iovecs and go direct-to-BIO for O_DIRECT */ |
2291 | if (unlikely(file->f_flags & O_DIRECT)) { | 2291 | if (unlikely(file->f_flags & O_DIRECT)) { |
2292 | written = generic_file_direct_write(iocb, iov, | 2292 | loff_t endbyte; |
2293 | &nr_segs, pos, ppos, count, ocount); | 2293 | ssize_t written_buffered; |
2294 | |||
2295 | written = generic_file_direct_write(iocb, iov, &nr_segs, pos, | ||
2296 | ppos, count, ocount); | ||
2294 | if (written < 0 || written == count) | 2297 | if (written < 0 || written == count) |
2295 | goto out; | 2298 | goto out; |
2296 | /* | 2299 | /* |
@@ -2299,10 +2302,46 @@ __generic_file_aio_write_nolock(struct kiocb *iocb, const struct iovec *iov, | |||
2299 | */ | 2302 | */ |
2300 | pos += written; | 2303 | pos += written; |
2301 | count -= written; | 2304 | count -= written; |
2302 | } | 2305 | written_buffered = generic_file_buffered_write(iocb, iov, |
2306 | nr_segs, pos, ppos, count, | ||
2307 | written); | ||
2308 | /* | ||
2309 | * If generic_file_buffered_write() retuned a synchronous error | ||
2310 | * then we want to return the number of bytes which were | ||
2311 | * direct-written, or the error code if that was zero. Note | ||
2312 | * that this differs from normal direct-io semantics, which | ||
2313 | * will return -EFOO even if some bytes were written. | ||
2314 | */ | ||
2315 | if (written_buffered < 0) { | ||
2316 | err = written_buffered; | ||
2317 | goto out; | ||
2318 | } | ||
2303 | 2319 | ||
2304 | written = generic_file_buffered_write(iocb, iov, nr_segs, | 2320 | /* |
2305 | pos, ppos, count, written); | 2321 | * We need to ensure that the page cache pages are written to |
2322 | * disk and invalidated to preserve the expected O_DIRECT | ||
2323 | * semantics. | ||
2324 | */ | ||
2325 | endbyte = pos + written_buffered - written - 1; | ||
2326 | err = do_sync_file_range(file, pos, endbyte, | ||
2327 | SYNC_FILE_RANGE_WAIT_BEFORE| | ||
2328 | SYNC_FILE_RANGE_WRITE| | ||
2329 | SYNC_FILE_RANGE_WAIT_AFTER); | ||
2330 | if (err == 0) { | ||
2331 | written = written_buffered; | ||
2332 | invalidate_mapping_pages(mapping, | ||
2333 | pos >> PAGE_CACHE_SHIFT, | ||
2334 | endbyte >> PAGE_CACHE_SHIFT); | ||
2335 | } else { | ||
2336 | /* | ||
2337 | * We don't know how much we wrote, so just return | ||
2338 | * the number of bytes which were direct-written | ||
2339 | */ | ||
2340 | } | ||
2341 | } else { | ||
2342 | written = generic_file_buffered_write(iocb, iov, nr_segs, | ||
2343 | pos, ppos, count, written); | ||
2344 | } | ||
2306 | out: | 2345 | out: |
2307 | current->backing_dev_info = NULL; | 2346 | current->backing_dev_info = NULL; |
2308 | return written ? written : err; | 2347 | return written ? written : err; |