diff --git a/block/fops.c b/block/fops.c index 5a559fcfadf9..52ebf5bd1443 100644 --- a/block/fops.c +++ b/block/fops.c @@ -782,9 +782,28 @@ static ssize_t blkdev_write_iter(struct kiocb *iocb, struct iov_iter *from) if (iocb->ki_flags & IOCB_DIRECT) { ret = blkdev_direct_write(iocb, from); if (ret >= 0 && iov_iter_count(from)) { - ret = direct_write_fallback(iocb, from, ret, - blkdev_buffered_write(iocb, from)); - need_sync = true; + if (iocb->ki_flags & IOCB_NOWAIT) { + /* + * The buffered fallback blocks on i_rwsem and + * on writeback of the data it copied: return + * the short direct write instead and let the + * caller retry. The bytes already written + * still need a flush if REQ_FUA was not set. + */ + if (!ret) + ret = -EAGAIN; + else if (!blkdev_dio_fua(iocb, bdev)) + need_sync = true; + } else { + ssize_t ret2; + + inode_lock_shared(bd_inode); + ret2 = blkdev_buffered_write(iocb, from); + inode_unlock_shared(bd_inode); + ret = direct_write_fallback(iocb, from, ret, + ret2); + need_sync = true; + } } else if (ret > 0 && !blkdev_dio_fua(iocb, bdev)) { /* * The device does not support FUA, so REQ_FUA was not