diff options
-rw-r--r-- | fs/fuse/file.c | 19 |
1 files changed, 13 insertions, 6 deletions
diff --git a/fs/fuse/file.c b/fs/fuse/file.c index ba1d50369c24..8f39f7b8cef2 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c | |||
@@ -1331,7 +1331,8 @@ EXPORT_SYMBOL_GPL(fuse_direct_io); | |||
1331 | 1331 | ||
1332 | static ssize_t __fuse_direct_read(struct fuse_io_priv *io, | 1332 | static ssize_t __fuse_direct_read(struct fuse_io_priv *io, |
1333 | const struct iovec *iov, | 1333 | const struct iovec *iov, |
1334 | unsigned long nr_segs, loff_t *ppos) | 1334 | unsigned long nr_segs, loff_t *ppos, |
1335 | size_t count) | ||
1335 | { | 1336 | { |
1336 | ssize_t res; | 1337 | ssize_t res; |
1337 | struct file *file = io->file; | 1338 | struct file *file = io->file; |
@@ -1340,8 +1341,7 @@ static ssize_t __fuse_direct_read(struct fuse_io_priv *io, | |||
1340 | if (is_bad_inode(inode)) | 1341 | if (is_bad_inode(inode)) |
1341 | return -EIO; | 1342 | return -EIO; |
1342 | 1343 | ||
1343 | res = fuse_direct_io(io, iov, nr_segs, iov_length(iov, nr_segs), | 1344 | res = fuse_direct_io(io, iov, nr_segs, count, ppos, 0); |
1344 | ppos, 0); | ||
1345 | 1345 | ||
1346 | fuse_invalidate_attr(inode); | 1346 | fuse_invalidate_attr(inode); |
1347 | 1347 | ||
@@ -1353,7 +1353,7 @@ static ssize_t fuse_direct_read(struct file *file, char __user *buf, | |||
1353 | { | 1353 | { |
1354 | struct fuse_io_priv io = { .async = 0, .file = file }; | 1354 | struct fuse_io_priv io = { .async = 0, .file = file }; |
1355 | struct iovec iov = { .iov_base = buf, .iov_len = count }; | 1355 | struct iovec iov = { .iov_base = buf, .iov_len = count }; |
1356 | return __fuse_direct_read(&io, &iov, 1, ppos); | 1356 | return __fuse_direct_read(&io, &iov, 1, ppos, count); |
1357 | } | 1357 | } |
1358 | 1358 | ||
1359 | static ssize_t __fuse_direct_write(struct fuse_io_priv *io, | 1359 | static ssize_t __fuse_direct_write(struct fuse_io_priv *io, |
@@ -2369,6 +2369,13 @@ fuse_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, | |||
2369 | inode = file->f_mapping->host; | 2369 | inode = file->f_mapping->host; |
2370 | i_size = i_size_read(inode); | 2370 | i_size = i_size_read(inode); |
2371 | 2371 | ||
2372 | /* optimization for short read */ | ||
2373 | if (rw != WRITE && offset + count > i_size) { | ||
2374 | if (offset >= i_size) | ||
2375 | return 0; | ||
2376 | count = i_size - offset; | ||
2377 | } | ||
2378 | |||
2372 | io = kmalloc(sizeof(struct fuse_io_priv), GFP_KERNEL); | 2379 | io = kmalloc(sizeof(struct fuse_io_priv), GFP_KERNEL); |
2373 | if (!io) | 2380 | if (!io) |
2374 | return -ENOMEM; | 2381 | return -ENOMEM; |
@@ -2392,13 +2399,13 @@ fuse_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, | |||
2392 | * to wait on real async I/O requests, so we must submit this request | 2399 | * to wait on real async I/O requests, so we must submit this request |
2393 | * synchronously. | 2400 | * synchronously. |
2394 | */ | 2401 | */ |
2395 | if (!is_sync_kiocb(iocb) && (offset + count > i_size) && rw == WRITE) | 2402 | if (!is_sync_kiocb(iocb) && (offset + count > i_size)) |
2396 | io->async = false; | 2403 | io->async = false; |
2397 | 2404 | ||
2398 | if (rw == WRITE) | 2405 | if (rw == WRITE) |
2399 | ret = __fuse_direct_write(io, iov, nr_segs, &pos); | 2406 | ret = __fuse_direct_write(io, iov, nr_segs, &pos); |
2400 | else | 2407 | else |
2401 | ret = __fuse_direct_read(io, iov, nr_segs, &pos); | 2408 | ret = __fuse_direct_read(io, iov, nr_segs, &pos, count); |
2402 | 2409 | ||
2403 | if (io->async) { | 2410 | if (io->async) { |
2404 | fuse_aio_complete(io, ret < 0 ? ret : 0, -1); | 2411 | fuse_aio_complete(io, ret < 0 ? ret : 0, -1); |