diff options
| -rw-r--r-- | fs/fuse/dir.c | 12 | ||||
| -rw-r--r-- | fs/fuse/file.c | 58 | ||||
| -rw-r--r-- | fs/fuse/inode.c | 7 |
3 files changed, 62 insertions, 15 deletions
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 254df56b847b..f3f783dc4f75 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c | |||
| @@ -180,6 +180,8 @@ u64 fuse_get_attr_version(struct fuse_conn *fc) | |||
| 180 | static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags) | 180 | static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags) |
| 181 | { | 181 | { |
| 182 | struct inode *inode; | 182 | struct inode *inode; |
| 183 | struct dentry *parent; | ||
| 184 | struct fuse_conn *fc; | ||
| 183 | 185 | ||
| 184 | inode = ACCESS_ONCE(entry->d_inode); | 186 | inode = ACCESS_ONCE(entry->d_inode); |
| 185 | if (inode && is_bad_inode(inode)) | 187 | if (inode && is_bad_inode(inode)) |
| @@ -187,10 +189,8 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags) | |||
| 187 | else if (fuse_dentry_time(entry) < get_jiffies_64()) { | 189 | else if (fuse_dentry_time(entry) < get_jiffies_64()) { |
| 188 | int err; | 190 | int err; |
| 189 | struct fuse_entry_out outarg; | 191 | struct fuse_entry_out outarg; |
| 190 | struct fuse_conn *fc; | ||
| 191 | struct fuse_req *req; | 192 | struct fuse_req *req; |
| 192 | struct fuse_forget_link *forget; | 193 | struct fuse_forget_link *forget; |
| 193 | struct dentry *parent; | ||
| 194 | u64 attr_version; | 194 | u64 attr_version; |
| 195 | 195 | ||
| 196 | /* For negative dentries, always do a fresh lookup */ | 196 | /* For negative dentries, always do a fresh lookup */ |
| @@ -241,8 +241,14 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags) | |||
| 241 | entry_attr_timeout(&outarg), | 241 | entry_attr_timeout(&outarg), |
| 242 | attr_version); | 242 | attr_version); |
| 243 | fuse_change_entry_timeout(entry, &outarg); | 243 | fuse_change_entry_timeout(entry, &outarg); |
| 244 | } else if (inode) { | ||
| 245 | fc = get_fuse_conn(inode); | ||
| 246 | if (fc->readdirplus_auto) { | ||
| 247 | parent = dget_parent(entry); | ||
| 248 | fuse_advise_use_readdirplus(parent->d_inode); | ||
| 249 | dput(parent); | ||
| 250 | } | ||
| 244 | } | 251 | } |
| 245 | fuse_advise_use_readdirplus(inode); | ||
| 246 | return 1; | 252 | return 1; |
| 247 | } | 253 | } |
| 248 | 254 | ||
diff --git a/fs/fuse/file.c b/fs/fuse/file.c index d1c9b85b3f58..e570081f9f76 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c | |||
| @@ -16,6 +16,7 @@ | |||
| 16 | #include <linux/compat.h> | 16 | #include <linux/compat.h> |
| 17 | #include <linux/swap.h> | 17 | #include <linux/swap.h> |
| 18 | #include <linux/aio.h> | 18 | #include <linux/aio.h> |
| 19 | #include <linux/falloc.h> | ||
| 19 | 20 | ||
| 20 | static const struct file_operations fuse_direct_io_file_operations; | 21 | static const struct file_operations fuse_direct_io_file_operations; |
| 21 | 22 | ||
| @@ -1278,7 +1279,10 @@ ssize_t fuse_direct_io(struct fuse_io_priv *io, const struct iovec *iov, | |||
| 1278 | 1279 | ||
| 1279 | iov_iter_init(&ii, iov, nr_segs, count, 0); | 1280 | iov_iter_init(&ii, iov, nr_segs, count, 0); |
| 1280 | 1281 | ||
| 1281 | req = fuse_get_req(fc, fuse_iter_npages(&ii)); | 1282 | if (io->async) |
| 1283 | req = fuse_get_req_for_background(fc, fuse_iter_npages(&ii)); | ||
| 1284 | else | ||
| 1285 | req = fuse_get_req(fc, fuse_iter_npages(&ii)); | ||
| 1282 | if (IS_ERR(req)) | 1286 | if (IS_ERR(req)) |
| 1283 | return PTR_ERR(req); | 1287 | return PTR_ERR(req); |
| 1284 | 1288 | ||
| @@ -1314,7 +1318,11 @@ ssize_t fuse_direct_io(struct fuse_io_priv *io, const struct iovec *iov, | |||
| 1314 | break; | 1318 | break; |
| 1315 | if (count) { | 1319 | if (count) { |
| 1316 | fuse_put_request(fc, req); | 1320 | fuse_put_request(fc, req); |
| 1317 | req = fuse_get_req(fc, fuse_iter_npages(&ii)); | 1321 | if (io->async) |
| 1322 | req = fuse_get_req_for_background(fc, | ||
| 1323 | fuse_iter_npages(&ii)); | ||
| 1324 | else | ||
| 1325 | req = fuse_get_req(fc, fuse_iter_npages(&ii)); | ||
| 1318 | if (IS_ERR(req)) | 1326 | if (IS_ERR(req)) |
| 1319 | break; | 1327 | break; |
| 1320 | } | 1328 | } |
| @@ -2365,6 +2373,11 @@ static void fuse_do_truncate(struct file *file) | |||
| 2365 | fuse_do_setattr(inode, &attr, file); | 2373 | fuse_do_setattr(inode, &attr, file); |
| 2366 | } | 2374 | } |
| 2367 | 2375 | ||
| 2376 | static inline loff_t fuse_round_up(loff_t off) | ||
| 2377 | { | ||
| 2378 | return round_up(off, FUSE_MAX_PAGES_PER_REQ << PAGE_SHIFT); | ||
| 2379 | } | ||
| 2380 | |||
| 2368 | static ssize_t | 2381 | static ssize_t |
| 2369 | fuse_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, | 2382 | fuse_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, |
| 2370 | loff_t offset, unsigned long nr_segs) | 2383 | loff_t offset, unsigned long nr_segs) |
| @@ -2372,6 +2385,7 @@ fuse_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, | |||
| 2372 | ssize_t ret = 0; | 2385 | ssize_t ret = 0; |
| 2373 | struct file *file = iocb->ki_filp; | 2386 | struct file *file = iocb->ki_filp; |
| 2374 | struct fuse_file *ff = file->private_data; | 2387 | struct fuse_file *ff = file->private_data; |
| 2388 | bool async_dio = ff->fc->async_dio; | ||
| 2375 | loff_t pos = 0; | 2389 | loff_t pos = 0; |
| 2376 | struct inode *inode; | 2390 | struct inode *inode; |
| 2377 | loff_t i_size; | 2391 | loff_t i_size; |
| @@ -2383,10 +2397,10 @@ fuse_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, | |||
| 2383 | i_size = i_size_read(inode); | 2397 | i_size = i_size_read(inode); |
| 2384 | 2398 | ||
| 2385 | /* optimization for short read */ | 2399 | /* optimization for short read */ |
| 2386 | if (rw != WRITE && offset + count > i_size) { | 2400 | if (async_dio && rw != WRITE && offset + count > i_size) { |
| 2387 | if (offset >= i_size) | 2401 | if (offset >= i_size) |
| 2388 | return 0; | 2402 | return 0; |
| 2389 | count = i_size - offset; | 2403 | count = min_t(loff_t, count, fuse_round_up(i_size - offset)); |
| 2390 | } | 2404 | } |
| 2391 | 2405 | ||
| 2392 | io = kmalloc(sizeof(struct fuse_io_priv), GFP_KERNEL); | 2406 | io = kmalloc(sizeof(struct fuse_io_priv), GFP_KERNEL); |
| @@ -2404,7 +2418,7 @@ fuse_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, | |||
| 2404 | * By default, we want to optimize all I/Os with async request | 2418 | * By default, we want to optimize all I/Os with async request |
| 2405 | * submission to the client filesystem if supported. | 2419 | * submission to the client filesystem if supported. |
| 2406 | */ | 2420 | */ |
| 2407 | io->async = ff->fc->async_dio; | 2421 | io->async = async_dio; |
| 2408 | io->iocb = iocb; | 2422 | io->iocb = iocb; |
| 2409 | 2423 | ||
| 2410 | /* | 2424 | /* |
| @@ -2412,7 +2426,7 @@ fuse_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, | |||
| 2412 | * to wait on real async I/O requests, so we must submit this request | 2426 | * to wait on real async I/O requests, so we must submit this request |
| 2413 | * synchronously. | 2427 | * synchronously. |
| 2414 | */ | 2428 | */ |
| 2415 | if (!is_sync_kiocb(iocb) && (offset + count > i_size)) | 2429 | if (!is_sync_kiocb(iocb) && (offset + count > i_size) && rw == WRITE) |
| 2416 | io->async = false; | 2430 | io->async = false; |
| 2417 | 2431 | ||
| 2418 | if (rw == WRITE) | 2432 | if (rw == WRITE) |
| @@ -2424,7 +2438,7 @@ fuse_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, | |||
| 2424 | fuse_aio_complete(io, ret < 0 ? ret : 0, -1); | 2438 | fuse_aio_complete(io, ret < 0 ? ret : 0, -1); |
| 2425 | 2439 | ||
| 2426 | /* we have a non-extending, async request, so return */ | 2440 | /* we have a non-extending, async request, so return */ |
| 2427 | if (ret > 0 && !is_sync_kiocb(iocb)) | 2441 | if (!is_sync_kiocb(iocb)) |
| 2428 | return -EIOCBQUEUED; | 2442 | return -EIOCBQUEUED; |
| 2429 | 2443 | ||
| 2430 | ret = wait_on_sync_kiocb(iocb); | 2444 | ret = wait_on_sync_kiocb(iocb); |
| @@ -2446,6 +2460,7 @@ static long fuse_file_fallocate(struct file *file, int mode, loff_t offset, | |||
| 2446 | loff_t length) | 2460 | loff_t length) |
| 2447 | { | 2461 | { |
| 2448 | struct fuse_file *ff = file->private_data; | 2462 | struct fuse_file *ff = file->private_data; |
| 2463 | struct inode *inode = file->f_inode; | ||
| 2449 | struct fuse_conn *fc = ff->fc; | 2464 | struct fuse_conn *fc = ff->fc; |
| 2450 | struct fuse_req *req; | 2465 | struct fuse_req *req; |
| 2451 | struct fuse_fallocate_in inarg = { | 2466 | struct fuse_fallocate_in inarg = { |
| @@ -2459,9 +2474,16 @@ static long fuse_file_fallocate(struct file *file, int mode, loff_t offset, | |||
| 2459 | if (fc->no_fallocate) | 2474 | if (fc->no_fallocate) |
| 2460 | return -EOPNOTSUPP; | 2475 | return -EOPNOTSUPP; |
| 2461 | 2476 | ||
| 2477 | if (mode & FALLOC_FL_PUNCH_HOLE) { | ||
| 2478 | mutex_lock(&inode->i_mutex); | ||
| 2479 | fuse_set_nowrite(inode); | ||
| 2480 | } | ||
| 2481 | |||
| 2462 | req = fuse_get_req_nopages(fc); | 2482 | req = fuse_get_req_nopages(fc); |
| 2463 | if (IS_ERR(req)) | 2483 | if (IS_ERR(req)) { |
| 2464 | return PTR_ERR(req); | 2484 | err = PTR_ERR(req); |
| 2485 | goto out; | ||
| 2486 | } | ||
| 2465 | 2487 | ||
| 2466 | req->in.h.opcode = FUSE_FALLOCATE; | 2488 | req->in.h.opcode = FUSE_FALLOCATE; |
| 2467 | req->in.h.nodeid = ff->nodeid; | 2489 | req->in.h.nodeid = ff->nodeid; |
| @@ -2476,6 +2498,24 @@ static long fuse_file_fallocate(struct file *file, int mode, loff_t offset, | |||
| 2476 | } | 2498 | } |
| 2477 | fuse_put_request(fc, req); | 2499 | fuse_put_request(fc, req); |
| 2478 | 2500 | ||
| 2501 | if (err) | ||
| 2502 | goto out; | ||
| 2503 | |||
| 2504 | /* we could have extended the file */ | ||
| 2505 | if (!(mode & FALLOC_FL_KEEP_SIZE)) | ||
| 2506 | fuse_write_update_size(inode, offset + length); | ||
| 2507 | |||
| 2508 | if (mode & FALLOC_FL_PUNCH_HOLE) | ||
| 2509 | truncate_pagecache_range(inode, offset, offset + length - 1); | ||
| 2510 | |||
| 2511 | fuse_invalidate_attr(inode); | ||
| 2512 | |||
| 2513 | out: | ||
| 2514 | if (mode & FALLOC_FL_PUNCH_HOLE) { | ||
| 2515 | fuse_release_nowrite(inode); | ||
| 2516 | mutex_unlock(&inode->i_mutex); | ||
| 2517 | } | ||
| 2518 | |||
| 2479 | return err; | 2519 | return err; |
| 2480 | } | 2520 | } |
| 2481 | 2521 | ||
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 6201f81e4d3a..9a0cdde14a08 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c | |||
| @@ -867,10 +867,11 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req) | |||
| 867 | fc->dont_mask = 1; | 867 | fc->dont_mask = 1; |
| 868 | if (arg->flags & FUSE_AUTO_INVAL_DATA) | 868 | if (arg->flags & FUSE_AUTO_INVAL_DATA) |
| 869 | fc->auto_inval_data = 1; | 869 | fc->auto_inval_data = 1; |
| 870 | if (arg->flags & FUSE_DO_READDIRPLUS) | 870 | if (arg->flags & FUSE_DO_READDIRPLUS) { |
| 871 | fc->do_readdirplus = 1; | 871 | fc->do_readdirplus = 1; |
| 872 | if (arg->flags & FUSE_READDIRPLUS_AUTO) | 872 | if (arg->flags & FUSE_READDIRPLUS_AUTO) |
| 873 | fc->readdirplus_auto = 1; | 873 | fc->readdirplus_auto = 1; |
| 874 | } | ||
| 874 | if (arg->flags & FUSE_ASYNC_DIO) | 875 | if (arg->flags & FUSE_ASYNC_DIO) |
| 875 | fc->async_dio = 1; | 876 | fc->async_dio = 1; |
| 876 | } else { | 877 | } else { |
