|
@@ -2222,7 +2222,7 @@ __generic_file_aio_write_nolock(struct kiocb *iocb, const struct iovec *iov,
|
|
unsigned long nr_segs, loff_t *ppos)
|
|
unsigned long nr_segs, loff_t *ppos)
|
|
{
|
|
{
|
|
struct file *file = iocb->ki_filp;
|
|
struct file *file = iocb->ki_filp;
|
|
- const struct address_space * mapping = file->f_mapping;
|
|
|
|
|
|
+ struct address_space * mapping = file->f_mapping;
|
|
size_t ocount; /* original count */
|
|
size_t ocount; /* original count */
|
|
size_t count; /* after file limit checks */
|
|
size_t count; /* after file limit checks */
|
|
struct inode *inode = mapping->host;
|
|
struct inode *inode = mapping->host;
|
|
@@ -2275,8 +2275,11 @@ __generic_file_aio_write_nolock(struct kiocb *iocb, const struct iovec *iov,
|
|
|
|
|
|
/* coalesce the iovecs and go direct-to-BIO for O_DIRECT */
|
|
/* coalesce the iovecs and go direct-to-BIO for O_DIRECT */
|
|
if (unlikely(file->f_flags & O_DIRECT)) {
|
|
if (unlikely(file->f_flags & O_DIRECT)) {
|
|
- written = generic_file_direct_write(iocb, iov,
|
|
|
|
- &nr_segs, pos, ppos, count, ocount);
|
|
|
|
|
|
+ loff_t endbyte;
|
|
|
|
+ ssize_t written_buffered;
|
|
|
|
+
|
|
|
|
+ written = generic_file_direct_write(iocb, iov, &nr_segs, pos,
|
|
|
|
+ ppos, count, ocount);
|
|
if (written < 0 || written == count)
|
|
if (written < 0 || written == count)
|
|
goto out;
|
|
goto out;
|
|
/*
|
|
/*
|
|
@@ -2285,10 +2288,46 @@ __generic_file_aio_write_nolock(struct kiocb *iocb, const struct iovec *iov,
|
|
*/
|
|
*/
|
|
pos += written;
|
|
pos += written;
|
|
count -= written;
|
|
count -= written;
|
|
- }
|
|
|
|
|
|
+ written_buffered = generic_file_buffered_write(iocb, iov,
|
|
|
|
+ nr_segs, pos, ppos, count,
|
|
|
|
+ written);
|
|
|
|
+ /*
|
|
|
|
+ * If generic_file_buffered_write() retuned a synchronous error
|
|
|
|
+ * then we want to return the number of bytes which were
|
|
|
|
+ * direct-written, or the error code if that was zero. Note
|
|
|
|
+ * that this differs from normal direct-io semantics, which
|
|
|
|
+ * will return -EFOO even if some bytes were written.
|
|
|
|
+ */
|
|
|
|
+ if (written_buffered < 0) {
|
|
|
|
+ err = written_buffered;
|
|
|
|
+ goto out;
|
|
|
|
+ }
|
|
|
|
|
|
- written = generic_file_buffered_write(iocb, iov, nr_segs,
|
|
|
|
- pos, ppos, count, written);
|
|
|
|
|
|
+ /*
|
|
|
|
+ * We need to ensure that the page cache pages are written to
|
|
|
|
+ * disk and invalidated to preserve the expected O_DIRECT
|
|
|
|
+ * semantics.
|
|
|
|
+ */
|
|
|
|
+ endbyte = pos + written_buffered - written - 1;
|
|
|
|
+ err = do_sync_file_range(file, pos, endbyte,
|
|
|
|
+ SYNC_FILE_RANGE_WAIT_BEFORE|
|
|
|
|
+ SYNC_FILE_RANGE_WRITE|
|
|
|
|
+ SYNC_FILE_RANGE_WAIT_AFTER);
|
|
|
|
+ if (err == 0) {
|
|
|
|
+ written = written_buffered;
|
|
|
|
+ invalidate_mapping_pages(mapping,
|
|
|
|
+ pos >> PAGE_CACHE_SHIFT,
|
|
|
|
+ endbyte >> PAGE_CACHE_SHIFT);
|
|
|
|
+ } else {
|
|
|
|
+ /*
|
|
|
|
+ * We don't know how much we wrote, so just return
|
|
|
|
+ * the number of bytes which were direct-written
|
|
|
|
+ */
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ written = generic_file_buffered_write(iocb, iov, nr_segs,
|
|
|
|
+ pos, ppos, count, written);
|
|
|
|
+ }
|
|
out:
|
|
out:
|
|
current->backing_dev_info = NULL;
|
|
current->backing_dev_info = NULL;
|
|
return written ? written : err;
|
|
return written ? written : err;
|