diff --git a/mm/filemap.c b/mm/filemap.c index d01abb6..96840e5 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -2058,8 +2058,9 @@ generic_file_direct_write(struct kiocb * /* * Sync the fs metadata but not the minor inode changes and * of course not the data as we did direct DMA for the IO. - * i_mutex is held, which protects generic_osync_inode() from - * livelocking. AIO O_DIRECT ops attempt to sync metadata here. + * i_mutex may not being held, if so some specific locking + * ordering must protect generic_osync_inode() from livelocking. + * AIO O_DIRECT ops attempt to sync metadata here. */ if ((written >= 0 || written == -EIOCBQUEUED) && ((file->f_flags & O_SYNC) || IS_SYNC(inode))) { @@ -2365,6 +2366,17 @@ ssize_t generic_file_aio_write(struct ki &iocb->ki_pos); mutex_unlock(&inode->i_mutex); + if (unlikely(ret < 0 && (file->f_flags & O_DIRECT))) { + ssize_t cnt = generic_segment_checks(nr_segs, iov, VERIFY_READ); + loff_t isize = i_size_read(inode); + /* + * generic_file_direct_write() may have instantiated a few + * blocks outside i_size. Trim these off again. + */ + if (cnt > 0 && (pos + cnt > isize)) + vmtruncate(inode, isize); + } + if (ret > 0 && ((file->f_flags & O_SYNC) || IS_SYNC(inode))) { ssize_t err; @@ -2377,8 +2389,8 @@ ssize_t generic_file_aio_write(struct ki EXPORT_SYMBOL(generic_file_aio_write); /* - * Called under i_mutex for writes to S_ISREG files. Returns -EIO if something - * went wrong during pagecache shootdown. + * May be called without i_mutex for writes to S_ISREG files. + * Returns -EIO if something went wrong during pagecache shootdown. */ static ssize_t generic_file_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,