diff options
author | Maxim Patlasov <mpatlasov@parallels.com> | 2012-12-14 10:20:51 -0500 |
---|---|---|
committer | Miklos Szeredi <mszeredi@suse.cz> | 2013-04-17 15:50:59 -0400 |
commit | 36cf66ed9f871fc0d0911921fba5873df3ddb2dc (patch) | |
tree | 8a449efaf4eeb9f0044258d926711d5ebb03416f /fs/fuse | |
parent | 01e9d11a3e79035ca5cd89b035435acd4ba61ee1 (diff) |
fuse: make fuse_direct_io() aware about AIO
The patch implements passing "struct fuse_io_priv *io" down the stack up to
fuse_send_read/write where it is used to submit request asynchronously.
io->async==0 designates synchronous processing.
Non-trivial part of the patch is changes in fuse_direct_io(): resources
like fuse requests and user pages cannot be released immediately in async
case.
Signed-off-by: Maxim Patlasov <mpatlasov@parallels.com>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
Diffstat (limited to 'fs/fuse')
-rw-r--r-- | fs/fuse/cuse.c | 6 | ||||
-rw-r--r-- | fs/fuse/dev.c | 2 | ||||
-rw-r--r-- | fs/fuse/file.c | 64 | ||||
-rw-r--r-- | fs/fuse/fuse_i.h | 7 |
4 files changed, 58 insertions, 21 deletions
diff --git a/fs/fuse/cuse.c b/fs/fuse/cuse.c index c59c097eb2e9..b3aaf7b3578b 100644 --- a/fs/fuse/cuse.c +++ b/fs/fuse/cuse.c | |||
@@ -92,8 +92,9 @@ static ssize_t cuse_read(struct file *file, char __user *buf, size_t count, | |||
92 | { | 92 | { |
93 | loff_t pos = 0; | 93 | loff_t pos = 0; |
94 | struct iovec iov = { .iov_base = buf, .iov_len = count }; | 94 | struct iovec iov = { .iov_base = buf, .iov_len = count }; |
95 | struct fuse_io_priv io = { .async = 0, .file = file }; | ||
95 | 96 | ||
96 | return fuse_direct_io(file, &iov, 1, count, &pos, 0); | 97 | return fuse_direct_io(&io, &iov, 1, count, &pos, 0); |
97 | } | 98 | } |
98 | 99 | ||
99 | static ssize_t cuse_write(struct file *file, const char __user *buf, | 100 | static ssize_t cuse_write(struct file *file, const char __user *buf, |
@@ -101,12 +102,13 @@ static ssize_t cuse_write(struct file *file, const char __user *buf, | |||
101 | { | 102 | { |
102 | loff_t pos = 0; | 103 | loff_t pos = 0; |
103 | struct iovec iov = { .iov_base = (void __user *)buf, .iov_len = count }; | 104 | struct iovec iov = { .iov_base = (void __user *)buf, .iov_len = count }; |
105 | struct fuse_io_priv io = { .async = 0, .file = file }; | ||
104 | 106 | ||
105 | /* | 107 | /* |
106 | * No locking or generic_write_checks(), the server is | 108 | * No locking or generic_write_checks(), the server is |
107 | * responsible for locking and sanity checks. | 109 | * responsible for locking and sanity checks. |
108 | */ | 110 | */ |
109 | return fuse_direct_io(file, &iov, 1, count, &pos, 1); | 111 | return fuse_direct_io(&io, &iov, 1, count, &pos, 1); |
110 | } | 112 | } |
111 | 113 | ||
112 | static int cuse_open(struct inode *inode, struct file *file) | 114 | static int cuse_open(struct inode *inode, struct file *file) |
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index be5c7e13320c..07bdb14ae7a3 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c | |||
@@ -111,7 +111,7 @@ static void restore_sigs(sigset_t *oldset) | |||
111 | sigprocmask(SIG_SETMASK, oldset, NULL); | 111 | sigprocmask(SIG_SETMASK, oldset, NULL); |
112 | } | 112 | } |
113 | 113 | ||
114 | static void __fuse_get_request(struct fuse_req *req) | 114 | void __fuse_get_request(struct fuse_req *req) |
115 | { | 115 | { |
116 | atomic_inc(&req->count); | 116 | atomic_inc(&req->count); |
117 | } | 117 | } |
diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 4002889fbcc1..e207dcdf32c0 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c | |||
@@ -593,14 +593,16 @@ static size_t fuse_async_req_send(struct fuse_conn *fc, struct fuse_req *req, | |||
593 | req->io = io; | 593 | req->io = io; |
594 | req->end = fuse_aio_complete_req; | 594 | req->end = fuse_aio_complete_req; |
595 | 595 | ||
596 | __fuse_get_request(req); | ||
596 | fuse_request_send_background(fc, req); | 597 | fuse_request_send_background(fc, req); |
597 | 598 | ||
598 | return num_bytes; | 599 | return num_bytes; |
599 | } | 600 | } |
600 | 601 | ||
601 | static size_t fuse_send_read(struct fuse_req *req, struct file *file, | 602 | static size_t fuse_send_read(struct fuse_req *req, struct fuse_io_priv *io, |
602 | loff_t pos, size_t count, fl_owner_t owner) | 603 | loff_t pos, size_t count, fl_owner_t owner) |
603 | { | 604 | { |
605 | struct file *file = io->file; | ||
604 | struct fuse_file *ff = file->private_data; | 606 | struct fuse_file *ff = file->private_data; |
605 | struct fuse_conn *fc = ff->fc; | 607 | struct fuse_conn *fc = ff->fc; |
606 | 608 | ||
@@ -611,6 +613,10 @@ static size_t fuse_send_read(struct fuse_req *req, struct file *file, | |||
611 | inarg->read_flags |= FUSE_READ_LOCKOWNER; | 613 | inarg->read_flags |= FUSE_READ_LOCKOWNER; |
612 | inarg->lock_owner = fuse_lock_owner_id(fc, owner); | 614 | inarg->lock_owner = fuse_lock_owner_id(fc, owner); |
613 | } | 615 | } |
616 | |||
617 | if (io->async) | ||
618 | return fuse_async_req_send(fc, req, count, io); | ||
619 | |||
614 | fuse_request_send(fc, req); | 620 | fuse_request_send(fc, req); |
615 | return req->out.args[0].size; | 621 | return req->out.args[0].size; |
616 | } | 622 | } |
@@ -631,6 +637,7 @@ static void fuse_read_update_size(struct inode *inode, loff_t size, | |||
631 | 637 | ||
632 | static int fuse_readpage(struct file *file, struct page *page) | 638 | static int fuse_readpage(struct file *file, struct page *page) |
633 | { | 639 | { |
640 | struct fuse_io_priv io = { .async = 0, .file = file }; | ||
634 | struct inode *inode = page->mapping->host; | 641 | struct inode *inode = page->mapping->host; |
635 | struct fuse_conn *fc = get_fuse_conn(inode); | 642 | struct fuse_conn *fc = get_fuse_conn(inode); |
636 | struct fuse_req *req; | 643 | struct fuse_req *req; |
@@ -663,7 +670,7 @@ static int fuse_readpage(struct file *file, struct page *page) | |||
663 | req->num_pages = 1; | 670 | req->num_pages = 1; |
664 | req->pages[0] = page; | 671 | req->pages[0] = page; |
665 | req->page_descs[0].length = count; | 672 | req->page_descs[0].length = count; |
666 | num_read = fuse_send_read(req, file, pos, count, NULL); | 673 | num_read = fuse_send_read(req, &io, pos, count, NULL); |
667 | err = req->out.h.error; | 674 | err = req->out.h.error; |
668 | fuse_put_request(fc, req); | 675 | fuse_put_request(fc, req); |
669 | 676 | ||
@@ -873,9 +880,10 @@ static void fuse_write_fill(struct fuse_req *req, struct fuse_file *ff, | |||
873 | req->out.args[0].value = outarg; | 880 | req->out.args[0].value = outarg; |
874 | } | 881 | } |
875 | 882 | ||
876 | static size_t fuse_send_write(struct fuse_req *req, struct file *file, | 883 | static size_t fuse_send_write(struct fuse_req *req, struct fuse_io_priv *io, |
877 | loff_t pos, size_t count, fl_owner_t owner) | 884 | loff_t pos, size_t count, fl_owner_t owner) |
878 | { | 885 | { |
886 | struct file *file = io->file; | ||
879 | struct fuse_file *ff = file->private_data; | 887 | struct fuse_file *ff = file->private_data; |
880 | struct fuse_conn *fc = ff->fc; | 888 | struct fuse_conn *fc = ff->fc; |
881 | struct fuse_write_in *inarg = &req->misc.write.in; | 889 | struct fuse_write_in *inarg = &req->misc.write.in; |
@@ -886,6 +894,10 @@ static size_t fuse_send_write(struct fuse_req *req, struct file *file, | |||
886 | inarg->write_flags |= FUSE_WRITE_LOCKOWNER; | 894 | inarg->write_flags |= FUSE_WRITE_LOCKOWNER; |
887 | inarg->lock_owner = fuse_lock_owner_id(fc, owner); | 895 | inarg->lock_owner = fuse_lock_owner_id(fc, owner); |
888 | } | 896 | } |
897 | |||
898 | if (io->async) | ||
899 | return fuse_async_req_send(fc, req, count, io); | ||
900 | |||
889 | fuse_request_send(fc, req); | 901 | fuse_request_send(fc, req); |
890 | return req->misc.write.out.size; | 902 | return req->misc.write.out.size; |
891 | } | 903 | } |
@@ -909,11 +921,12 @@ static size_t fuse_send_write_pages(struct fuse_req *req, struct file *file, | |||
909 | size_t res; | 921 | size_t res; |
910 | unsigned offset; | 922 | unsigned offset; |
911 | unsigned i; | 923 | unsigned i; |
924 | struct fuse_io_priv io = { .async = 0, .file = file }; | ||
912 | 925 | ||
913 | for (i = 0; i < req->num_pages; i++) | 926 | for (i = 0; i < req->num_pages; i++) |
914 | fuse_wait_on_page_writeback(inode, req->pages[i]->index); | 927 | fuse_wait_on_page_writeback(inode, req->pages[i]->index); |
915 | 928 | ||
916 | res = fuse_send_write(req, file, pos, count, NULL); | 929 | res = fuse_send_write(req, &io, pos, count, NULL); |
917 | 930 | ||
918 | offset = req->page_descs[0].offset; | 931 | offset = req->page_descs[0].offset; |
919 | count = res; | 932 | count = res; |
@@ -1251,10 +1264,11 @@ static inline int fuse_iter_npages(const struct iov_iter *ii_p) | |||
1251 | return min(npages, FUSE_MAX_PAGES_PER_REQ); | 1264 | return min(npages, FUSE_MAX_PAGES_PER_REQ); |
1252 | } | 1265 | } |
1253 | 1266 | ||
1254 | ssize_t fuse_direct_io(struct file *file, const struct iovec *iov, | 1267 | ssize_t fuse_direct_io(struct fuse_io_priv *io, const struct iovec *iov, |
1255 | unsigned long nr_segs, size_t count, loff_t *ppos, | 1268 | unsigned long nr_segs, size_t count, loff_t *ppos, |
1256 | int write) | 1269 | int write) |
1257 | { | 1270 | { |
1271 | struct file *file = io->file; | ||
1258 | struct fuse_file *ff = file->private_data; | 1272 | struct fuse_file *ff = file->private_data; |
1259 | struct fuse_conn *fc = ff->fc; | 1273 | struct fuse_conn *fc = ff->fc; |
1260 | size_t nmax = write ? fc->max_write : fc->max_read; | 1274 | size_t nmax = write ? fc->max_write : fc->max_read; |
@@ -1280,11 +1294,12 @@ ssize_t fuse_direct_io(struct file *file, const struct iovec *iov, | |||
1280 | } | 1294 | } |
1281 | 1295 | ||
1282 | if (write) | 1296 | if (write) |
1283 | nres = fuse_send_write(req, file, pos, nbytes, owner); | 1297 | nres = fuse_send_write(req, io, pos, nbytes, owner); |
1284 | else | 1298 | else |
1285 | nres = fuse_send_read(req, file, pos, nbytes, owner); | 1299 | nres = fuse_send_read(req, io, pos, nbytes, owner); |
1286 | 1300 | ||
1287 | fuse_release_user_pages(req, !write); | 1301 | if (!io->async) |
1302 | fuse_release_user_pages(req, !write); | ||
1288 | if (req->out.h.error) { | 1303 | if (req->out.h.error) { |
1289 | if (!res) | 1304 | if (!res) |
1290 | res = req->out.h.error; | 1305 | res = req->out.h.error; |
@@ -1314,16 +1329,18 @@ ssize_t fuse_direct_io(struct file *file, const struct iovec *iov, | |||
1314 | } | 1329 | } |
1315 | EXPORT_SYMBOL_GPL(fuse_direct_io); | 1330 | EXPORT_SYMBOL_GPL(fuse_direct_io); |
1316 | 1331 | ||
1317 | static ssize_t __fuse_direct_read(struct file *file, const struct iovec *iov, | 1332 | static ssize_t __fuse_direct_read(struct fuse_io_priv *io, |
1333 | const struct iovec *iov, | ||
1318 | unsigned long nr_segs, loff_t *ppos) | 1334 | unsigned long nr_segs, loff_t *ppos) |
1319 | { | 1335 | { |
1320 | ssize_t res; | 1336 | ssize_t res; |
1337 | struct file *file = io->file; | ||
1321 | struct inode *inode = file_inode(file); | 1338 | struct inode *inode = file_inode(file); |
1322 | 1339 | ||
1323 | if (is_bad_inode(inode)) | 1340 | if (is_bad_inode(inode)) |
1324 | return -EIO; | 1341 | return -EIO; |
1325 | 1342 | ||
1326 | res = fuse_direct_io(file, iov, nr_segs, iov_length(iov, nr_segs), | 1343 | res = fuse_direct_io(io, iov, nr_segs, iov_length(iov, nr_segs), |
1327 | ppos, 0); | 1344 | ppos, 0); |
1328 | 1345 | ||
1329 | fuse_invalidate_attr(inode); | 1346 | fuse_invalidate_attr(inode); |
@@ -1334,21 +1351,24 @@ static ssize_t __fuse_direct_read(struct file *file, const struct iovec *iov, | |||
1334 | static ssize_t fuse_direct_read(struct file *file, char __user *buf, | 1351 | static ssize_t fuse_direct_read(struct file *file, char __user *buf, |
1335 | size_t count, loff_t *ppos) | 1352 | size_t count, loff_t *ppos) |
1336 | { | 1353 | { |
1354 | struct fuse_io_priv io = { .async = 0, .file = file }; | ||
1337 | struct iovec iov = { .iov_base = buf, .iov_len = count }; | 1355 | struct iovec iov = { .iov_base = buf, .iov_len = count }; |
1338 | return __fuse_direct_read(file, &iov, 1, ppos); | 1356 | return __fuse_direct_read(&io, &iov, 1, ppos); |
1339 | } | 1357 | } |
1340 | 1358 | ||
1341 | static ssize_t __fuse_direct_write(struct file *file, const struct iovec *iov, | 1359 | static ssize_t __fuse_direct_write(struct fuse_io_priv *io, |
1360 | const struct iovec *iov, | ||
1342 | unsigned long nr_segs, loff_t *ppos) | 1361 | unsigned long nr_segs, loff_t *ppos) |
1343 | { | 1362 | { |
1363 | struct file *file = io->file; | ||
1344 | struct inode *inode = file_inode(file); | 1364 | struct inode *inode = file_inode(file); |
1345 | size_t count = iov_length(iov, nr_segs); | 1365 | size_t count = iov_length(iov, nr_segs); |
1346 | ssize_t res; | 1366 | ssize_t res; |
1347 | 1367 | ||
1348 | res = generic_write_checks(file, ppos, &count, 0); | 1368 | res = generic_write_checks(file, ppos, &count, 0); |
1349 | if (!res) { | 1369 | if (!res) { |
1350 | res = fuse_direct_io(file, iov, nr_segs, count, ppos, 1); | 1370 | res = fuse_direct_io(io, iov, nr_segs, count, ppos, 1); |
1351 | if (res > 0) | 1371 | if (!io->async && res > 0) |
1352 | fuse_write_update_size(inode, *ppos); | 1372 | fuse_write_update_size(inode, *ppos); |
1353 | } | 1373 | } |
1354 | 1374 | ||
@@ -1363,13 +1383,14 @@ static ssize_t fuse_direct_write(struct file *file, const char __user *buf, | |||
1363 | struct iovec iov = { .iov_base = (void __user *)buf, .iov_len = count }; | 1383 | struct iovec iov = { .iov_base = (void __user *)buf, .iov_len = count }; |
1364 | struct inode *inode = file_inode(file); | 1384 | struct inode *inode = file_inode(file); |
1365 | ssize_t res; | 1385 | ssize_t res; |
1386 | struct fuse_io_priv io = { .async = 0, .file = file }; | ||
1366 | 1387 | ||
1367 | if (is_bad_inode(inode)) | 1388 | if (is_bad_inode(inode)) |
1368 | return -EIO; | 1389 | return -EIO; |
1369 | 1390 | ||
1370 | /* Don't allow parallel writes to the same file */ | 1391 | /* Don't allow parallel writes to the same file */ |
1371 | mutex_lock(&inode->i_mutex); | 1392 | mutex_lock(&inode->i_mutex); |
1372 | res = __fuse_direct_write(file, &iov, 1, ppos); | 1393 | res = __fuse_direct_write(&io, &iov, 1, ppos); |
1373 | mutex_unlock(&inode->i_mutex); | 1394 | mutex_unlock(&inode->i_mutex); |
1374 | 1395 | ||
1375 | return res; | 1396 | return res; |
@@ -2339,14 +2360,23 @@ fuse_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, | |||
2339 | ssize_t ret = 0; | 2360 | ssize_t ret = 0; |
2340 | struct file *file = NULL; | 2361 | struct file *file = NULL; |
2341 | loff_t pos = 0; | 2362 | loff_t pos = 0; |
2363 | struct fuse_io_priv *io; | ||
2342 | 2364 | ||
2343 | file = iocb->ki_filp; | 2365 | file = iocb->ki_filp; |
2344 | pos = offset; | 2366 | pos = offset; |
2345 | 2367 | ||
2368 | io = kzalloc(sizeof(struct fuse_io_priv), GFP_KERNEL); | ||
2369 | if (!io) | ||
2370 | return -ENOMEM; | ||
2371 | |||
2372 | io->file = file; | ||
2373 | |||
2346 | if (rw == WRITE) | 2374 | if (rw == WRITE) |
2347 | ret = __fuse_direct_write(file, iov, nr_segs, &pos); | 2375 | ret = __fuse_direct_write(io, iov, nr_segs, &pos); |
2348 | else | 2376 | else |
2349 | ret = __fuse_direct_read(file, iov, nr_segs, &pos); | 2377 | ret = __fuse_direct_read(io, iov, nr_segs, &pos); |
2378 | |||
2379 | kfree(io); | ||
2350 | 2380 | ||
2351 | return ret; | 2381 | return ret; |
2352 | } | 2382 | } |
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index aea072413c47..337169a406c9 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h | |||
@@ -732,6 +732,11 @@ struct fuse_req *fuse_get_req(struct fuse_conn *fc, unsigned npages); | |||
732 | struct fuse_req *fuse_get_req_for_background(struct fuse_conn *fc, | 732 | struct fuse_req *fuse_get_req_for_background(struct fuse_conn *fc, |
733 | unsigned npages); | 733 | unsigned npages); |
734 | 734 | ||
735 | /* | ||
736 | * Increment reference count on request | ||
737 | */ | ||
738 | void __fuse_get_request(struct fuse_req *req); | ||
739 | |||
735 | /** | 740 | /** |
736 | * Get a request, may fail with -ENOMEM, | 741 | * Get a request, may fail with -ENOMEM, |
737 | * useful for callers who doesn't use req->pages[] | 742 | * useful for callers who doesn't use req->pages[] |
@@ -846,7 +851,7 @@ int fuse_reverse_inval_entry(struct super_block *sb, u64 parent_nodeid, | |||
846 | 851 | ||
847 | int fuse_do_open(struct fuse_conn *fc, u64 nodeid, struct file *file, | 852 | int fuse_do_open(struct fuse_conn *fc, u64 nodeid, struct file *file, |
848 | bool isdir); | 853 | bool isdir); |
849 | ssize_t fuse_direct_io(struct file *file, const struct iovec *iov, | 854 | ssize_t fuse_direct_io(struct fuse_io_priv *io, const struct iovec *iov, |
850 | unsigned long nr_segs, size_t count, loff_t *ppos, | 855 | unsigned long nr_segs, size_t count, loff_t *ppos, |
851 | int write); | 856 | int write); |
852 | long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg, | 857 | long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg, |