aboutsummaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
Diffstat (limited to 'mm')
-rw-r--r--mm/filemap.c51
1 files changed, 45 insertions, 6 deletions
diff --git a/mm/filemap.c b/mm/filemap.c
index 3464b681f844..57faa8d12099 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -2222,7 +2222,7 @@ __generic_file_aio_write_nolock(struct kiocb *iocb, const struct iovec *iov,
2222 unsigned long nr_segs, loff_t *ppos) 2222 unsigned long nr_segs, loff_t *ppos)
2223{ 2223{
2224 struct file *file = iocb->ki_filp; 2224 struct file *file = iocb->ki_filp;
2225 const struct address_space * mapping = file->f_mapping; 2225 struct address_space * mapping = file->f_mapping;
2226 size_t ocount; /* original count */ 2226 size_t ocount; /* original count */
2227 size_t count; /* after file limit checks */ 2227 size_t count; /* after file limit checks */
2228 struct inode *inode = mapping->host; 2228 struct inode *inode = mapping->host;
@@ -2275,8 +2275,11 @@ __generic_file_aio_write_nolock(struct kiocb *iocb, const struct iovec *iov,
2275 2275
2276 /* coalesce the iovecs and go direct-to-BIO for O_DIRECT */ 2276 /* coalesce the iovecs and go direct-to-BIO for O_DIRECT */
2277 if (unlikely(file->f_flags & O_DIRECT)) { 2277 if (unlikely(file->f_flags & O_DIRECT)) {
2278 written = generic_file_direct_write(iocb, iov, 2278 loff_t endbyte;
2279 &nr_segs, pos, ppos, count, ocount); 2279 ssize_t written_buffered;
2280
2281 written = generic_file_direct_write(iocb, iov, &nr_segs, pos,
2282 ppos, count, ocount);
2280 if (written < 0 || written == count) 2283 if (written < 0 || written == count)
2281 goto out; 2284 goto out;
2282 /* 2285 /*
@@ -2285,10 +2288,46 @@ __generic_file_aio_write_nolock(struct kiocb *iocb, const struct iovec *iov,
2285 */ 2288 */
2286 pos += written; 2289 pos += written;
2287 count -= written; 2290 count -= written;
2288 } 2291 written_buffered = generic_file_buffered_write(iocb, iov,
2292 nr_segs, pos, ppos, count,
2293 written);
2294 /*
2295 * If generic_file_buffered_write() retuned a synchronous error
2296 * then we want to return the number of bytes which were
2297 * direct-written, or the error code if that was zero. Note
2298 * that this differs from normal direct-io semantics, which
2299 * will return -EFOO even if some bytes were written.
2300 */
2301 if (written_buffered < 0) {
2302 err = written_buffered;
2303 goto out;
2304 }
2289 2305
2290 written = generic_file_buffered_write(iocb, iov, nr_segs, 2306 /*
2291 pos, ppos, count, written); 2307 * We need to ensure that the page cache pages are written to
2308 * disk and invalidated to preserve the expected O_DIRECT
2309 * semantics.
2310 */
2311 endbyte = pos + written_buffered - written - 1;
2312 err = do_sync_file_range(file, pos, endbyte,
2313 SYNC_FILE_RANGE_WAIT_BEFORE|
2314 SYNC_FILE_RANGE_WRITE|
2315 SYNC_FILE_RANGE_WAIT_AFTER);
2316 if (err == 0) {
2317 written = written_buffered;
2318 invalidate_mapping_pages(mapping,
2319 pos >> PAGE_CACHE_SHIFT,
2320 endbyte >> PAGE_CACHE_SHIFT);
2321 } else {
2322 /*
2323 * We don't know how much we wrote, so just return
2324 * the number of bytes which were direct-written
2325 */
2326 }
2327 } else {
2328 written = generic_file_buffered_write(iocb, iov, nr_segs,
2329 pos, ppos, count, written);
2330 }
2292out: 2331out:
2293 current->backing_dev_info = NULL; 2332 current->backing_dev_info = NULL;
2294 return written ? written : err; 2333 return written ? written : err;