aboutsummaryrefslogtreecommitdiffstats
path: root/fs/fuse
diff options
context:
space:
mode:
authorMaxim Patlasov <MPatlasov@parallels.com>2013-10-02 13:38:32 -0400
committerMiklos Szeredi <mszeredi@suse.cz>2013-11-05 04:11:27 -0500
commit6eaf4782eb09e28dbd13d23b9ce0fb7646daf37e (patch)
tree10416e984f694f35454238a2b7f1b8f72a214bdb /fs/fuse
parentf6011081f5e290756bd90fe96f1e86d3eac76f77 (diff)
fuse: writepages: crop secondary requests
If writeback happens while fuse is in FUSE_NOWRITE condition, the request will be queued but not processed immediately (see fuse_flush_writepages()). Until FUSE_NOWRITE becomes relaxed, more writebacks can happen. They will be queued as "secondary" requests to that first ("primary") request. Existing implementation crops only primary request. This is not correct because a subsequent extending write(2) may increase i_size and then secondary requests won't be cropped properly. The result would be stale data written to the server to a file offset where zeros must be. Similar problem may happen if secondary requests are attached to an in-flight request that was already cropped. The patch solves the issue by cropping all secondary requests in fuse_writepage_end(). Thanks to Miklos for idea. 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/file.c36
1 files changed, 31 insertions, 5 deletions
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 077b03844998..1cb303eba4d0 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -1436,12 +1436,12 @@ static void fuse_writepage_finish(struct fuse_conn *fc, struct fuse_req *req)
1436} 1436}
1437 1437
1438/* Called under fc->lock, may release and reacquire it */ 1438/* Called under fc->lock, may release and reacquire it */
1439static void fuse_send_writepage(struct fuse_conn *fc, struct fuse_req *req) 1439static void fuse_send_writepage(struct fuse_conn *fc, struct fuse_req *req,
1440 loff_t size)
1440__releases(fc->lock) 1441__releases(fc->lock)
1441__acquires(fc->lock) 1442__acquires(fc->lock)
1442{ 1443{
1443 struct fuse_inode *fi = get_fuse_inode(req->inode); 1444 struct fuse_inode *fi = get_fuse_inode(req->inode);
1444 loff_t size = i_size_read(req->inode);
1445 struct fuse_write_in *inarg = &req->misc.write.in; 1445 struct fuse_write_in *inarg = &req->misc.write.in;
1446 __u64 data_size = req->num_pages * PAGE_CACHE_SIZE; 1446 __u64 data_size = req->num_pages * PAGE_CACHE_SIZE;
1447 1447
@@ -1482,12 +1482,13 @@ __acquires(fc->lock)
1482{ 1482{
1483 struct fuse_conn *fc = get_fuse_conn(inode); 1483 struct fuse_conn *fc = get_fuse_conn(inode);
1484 struct fuse_inode *fi = get_fuse_inode(inode); 1484 struct fuse_inode *fi = get_fuse_inode(inode);
1485 size_t crop = i_size_read(inode);
1485 struct fuse_req *req; 1486 struct fuse_req *req;
1486 1487
1487 while (fi->writectr >= 0 && !list_empty(&fi->queued_writes)) { 1488 while (fi->writectr >= 0 && !list_empty(&fi->queued_writes)) {
1488 req = list_entry(fi->queued_writes.next, struct fuse_req, list); 1489 req = list_entry(fi->queued_writes.next, struct fuse_req, list);
1489 list_del_init(&req->list); 1490 list_del_init(&req->list);
1490 fuse_send_writepage(fc, req); 1491 fuse_send_writepage(fc, req, crop);
1491 } 1492 }
1492} 1493}
1493 1494
@@ -1499,12 +1500,37 @@ static void fuse_writepage_end(struct fuse_conn *fc, struct fuse_req *req)
1499 mapping_set_error(inode->i_mapping, req->out.h.error); 1500 mapping_set_error(inode->i_mapping, req->out.h.error);
1500 spin_lock(&fc->lock); 1501 spin_lock(&fc->lock);
1501 while (req->misc.write.next) { 1502 while (req->misc.write.next) {
1503 struct fuse_conn *fc = get_fuse_conn(inode);
1504 struct fuse_write_in *inarg = &req->misc.write.in;
1502 struct fuse_req *next = req->misc.write.next; 1505 struct fuse_req *next = req->misc.write.next;
1503 req->misc.write.next = next->misc.write.next; 1506 req->misc.write.next = next->misc.write.next;
1504 next->misc.write.next = NULL; 1507 next->misc.write.next = NULL;
1505 list_add(&next->writepages_entry, &fi->writepages); 1508 list_add(&next->writepages_entry, &fi->writepages);
1506 list_add_tail(&next->list, &fi->queued_writes); 1509
1507 fuse_flush_writepages(inode); 1510 /*
1511 * Skip fuse_flush_writepages() to make it easy to crop requests
1512 * based on primary request size.
1513 *
1514 * 1st case (trivial): there are no concurrent activities using
1515 * fuse_set/release_nowrite. Then we're on safe side because
1516 * fuse_flush_writepages() would call fuse_send_writepage()
1517 * anyway.
1518 *
1519 * 2nd case: someone called fuse_set_nowrite and it is waiting
1520 * now for completion of all in-flight requests. This happens
1521 * rarely and no more than once per page, so this should be
1522 * okay.
1523 *
1524 * 3rd case: someone (e.g. fuse_do_setattr()) is in the middle
1525 * of fuse_set_nowrite..fuse_release_nowrite section. The fact
1526 * that fuse_set_nowrite returned implies that all in-flight
1527 * requests were completed along with all of their secondary
1528 * requests. Further primary requests are blocked by negative
1529 * writectr. Hence there cannot be any in-flight requests and
1530 * no invocations of fuse_writepage_end() while we're in
1531 * fuse_set_nowrite..fuse_release_nowrite section.
1532 */
1533 fuse_send_writepage(fc, next, inarg->offset + inarg->size);
1508 } 1534 }
1509 fi->writectr--; 1535 fi->writectr--;
1510 fuse_writepage_finish(fc, req); 1536 fuse_writepage_finish(fc, req);