diff options
| -rw-r--r-- | Documentation/devices.txt | 1 | ||||
| -rw-r--r-- | fs/fuse/cuse.c | 5 | ||||
| -rw-r--r-- | fs/fuse/file.c | 361 | ||||
| -rw-r--r-- | fs/fuse/fuse_i.h | 1 | ||||
| -rw-r--r-- | include/linux/miscdevice.h | 1 |
5 files changed, 342 insertions, 27 deletions
diff --git a/Documentation/devices.txt b/Documentation/devices.txt index 23721d3be3e6..80b72419ffd8 100644 --- a/Documentation/devices.txt +++ b/Documentation/devices.txt | |||
| @@ -414,6 +414,7 @@ Your cooperation is appreciated. | |||
| 414 | 200 = /dev/net/tun TAP/TUN network device | 414 | 200 = /dev/net/tun TAP/TUN network device |
| 415 | 201 = /dev/button/gulpb Transmeta GULP-B buttons | 415 | 201 = /dev/button/gulpb Transmeta GULP-B buttons |
| 416 | 202 = /dev/emd/ctl Enhanced Metadisk RAID (EMD) control | 416 | 202 = /dev/emd/ctl Enhanced Metadisk RAID (EMD) control |
| 417 | 203 = /dev/cuse Cuse (character device in user-space) | ||
| 417 | 204 = /dev/video/em8300 EM8300 DVD decoder control | 418 | 204 = /dev/video/em8300 EM8300 DVD decoder control |
| 418 | 205 = /dev/video/em8300_mv EM8300 DVD decoder video | 419 | 205 = /dev/video/em8300_mv EM8300 DVD decoder video |
| 419 | 206 = /dev/video/em8300_ma EM8300 DVD decoder audio | 420 | 206 = /dev/video/em8300_ma EM8300 DVD decoder audio |
diff --git a/fs/fuse/cuse.c b/fs/fuse/cuse.c index adbfd66b380f..24da581cb52b 100644 --- a/fs/fuse/cuse.c +++ b/fs/fuse/cuse.c | |||
| @@ -589,11 +589,14 @@ static struct attribute *cuse_class_dev_attrs[] = { | |||
| 589 | ATTRIBUTE_GROUPS(cuse_class_dev); | 589 | ATTRIBUTE_GROUPS(cuse_class_dev); |
| 590 | 590 | ||
| 591 | static struct miscdevice cuse_miscdev = { | 591 | static struct miscdevice cuse_miscdev = { |
| 592 | .minor = MISC_DYNAMIC_MINOR, | 592 | .minor = CUSE_MINOR, |
| 593 | .name = "cuse", | 593 | .name = "cuse", |
| 594 | .fops = &cuse_channel_fops, | 594 | .fops = &cuse_channel_fops, |
| 595 | }; | 595 | }; |
| 596 | 596 | ||
| 597 | MODULE_ALIAS_MISCDEV(CUSE_MINOR); | ||
| 598 | MODULE_ALIAS("devname:cuse"); | ||
| 599 | |||
| 597 | static int __init cuse_init(void) | 600 | static int __init cuse_init(void) |
| 598 | { | 601 | { |
| 599 | int i, rc; | 602 | int i, rc; |
diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 4598345ab87d..7e70506297bc 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c | |||
| @@ -334,7 +334,8 @@ static bool fuse_page_is_writeback(struct inode *inode, pgoff_t index) | |||
| 334 | 334 | ||
| 335 | BUG_ON(req->inode != inode); | 335 | BUG_ON(req->inode != inode); |
| 336 | curr_index = req->misc.write.in.offset >> PAGE_CACHE_SHIFT; | 336 | curr_index = req->misc.write.in.offset >> PAGE_CACHE_SHIFT; |
| 337 | if (curr_index == index) { | 337 | if (curr_index <= index && |
| 338 | index < curr_index + req->num_pages) { | ||
| 338 | found = true; | 339 | found = true; |
| 339 | break; | 340 | break; |
| 340 | } | 341 | } |
| @@ -1409,8 +1410,13 @@ static ssize_t fuse_direct_write(struct file *file, const char __user *buf, | |||
| 1409 | 1410 | ||
| 1410 | static void fuse_writepage_free(struct fuse_conn *fc, struct fuse_req *req) | 1411 | static void fuse_writepage_free(struct fuse_conn *fc, struct fuse_req *req) |
| 1411 | { | 1412 | { |
| 1412 | __free_page(req->pages[0]); | 1413 | int i; |
| 1413 | fuse_file_put(req->ff, false); | 1414 | |
| 1415 | for (i = 0; i < req->num_pages; i++) | ||
| 1416 | __free_page(req->pages[i]); | ||
| 1417 | |||
| 1418 | if (req->ff) | ||
| 1419 | fuse_file_put(req->ff, false); | ||
| 1414 | } | 1420 | } |
| 1415 | 1421 | ||
| 1416 | static void fuse_writepage_finish(struct fuse_conn *fc, struct fuse_req *req) | 1422 | static void fuse_writepage_finish(struct fuse_conn *fc, struct fuse_req *req) |
| @@ -1418,30 +1424,34 @@ static void fuse_writepage_finish(struct fuse_conn *fc, struct fuse_req *req) | |||
| 1418 | struct inode *inode = req->inode; | 1424 | struct inode *inode = req->inode; |
| 1419 | struct fuse_inode *fi = get_fuse_inode(inode); | 1425 | struct fuse_inode *fi = get_fuse_inode(inode); |
| 1420 | struct backing_dev_info *bdi = inode->i_mapping->backing_dev_info; | 1426 | struct backing_dev_info *bdi = inode->i_mapping->backing_dev_info; |
| 1427 | int i; | ||
| 1421 | 1428 | ||
| 1422 | list_del(&req->writepages_entry); | 1429 | list_del(&req->writepages_entry); |
| 1423 | dec_bdi_stat(bdi, BDI_WRITEBACK); | 1430 | for (i = 0; i < req->num_pages; i++) { |
| 1424 | dec_zone_page_state(req->pages[0], NR_WRITEBACK_TEMP); | 1431 | dec_bdi_stat(bdi, BDI_WRITEBACK); |
| 1425 | bdi_writeout_inc(bdi); | 1432 | dec_zone_page_state(req->pages[i], NR_WRITEBACK_TEMP); |
| 1433 | bdi_writeout_inc(bdi); | ||
| 1434 | } | ||
| 1426 | wake_up(&fi->page_waitq); | 1435 | wake_up(&fi->page_waitq); |
| 1427 | } | 1436 | } |
| 1428 | 1437 | ||
| 1429 | /* Called under fc->lock, may release and reacquire it */ | 1438 | /* Called under fc->lock, may release and reacquire it */ |
| 1430 | static void fuse_send_writepage(struct fuse_conn *fc, struct fuse_req *req) | 1439 | static void fuse_send_writepage(struct fuse_conn *fc, struct fuse_req *req, |
| 1440 | loff_t size) | ||
| 1431 | __releases(fc->lock) | 1441 | __releases(fc->lock) |
| 1432 | __acquires(fc->lock) | 1442 | __acquires(fc->lock) |
| 1433 | { | 1443 | { |
| 1434 | struct fuse_inode *fi = get_fuse_inode(req->inode); | 1444 | struct fuse_inode *fi = get_fuse_inode(req->inode); |
| 1435 | loff_t size = i_size_read(req->inode); | ||
| 1436 | 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; | ||
| 1437 | 1447 | ||
| 1438 | if (!fc->connected) | 1448 | if (!fc->connected) |
| 1439 | goto out_free; | 1449 | goto out_free; |
| 1440 | 1450 | ||
| 1441 | if (inarg->offset + PAGE_CACHE_SIZE <= size) { | 1451 | if (inarg->offset + data_size <= size) { |
| 1442 | inarg->size = PAGE_CACHE_SIZE; | 1452 | inarg->size = data_size; |
| 1443 | } else if (inarg->offset < size) { | 1453 | } else if (inarg->offset < size) { |
| 1444 | inarg->size = size & (PAGE_CACHE_SIZE - 1); | 1454 | inarg->size = size - inarg->offset; |
| 1445 | } else { | 1455 | } else { |
| 1446 | /* Got truncated off completely */ | 1456 | /* Got truncated off completely */ |
| 1447 | goto out_free; | 1457 | goto out_free; |
| @@ -1472,12 +1482,13 @@ __acquires(fc->lock) | |||
| 1472 | { | 1482 | { |
| 1473 | struct fuse_conn *fc = get_fuse_conn(inode); | 1483 | struct fuse_conn *fc = get_fuse_conn(inode); |
| 1474 | 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); | ||
| 1475 | struct fuse_req *req; | 1486 | struct fuse_req *req; |
| 1476 | 1487 | ||
| 1477 | while (fi->writectr >= 0 && !list_empty(&fi->queued_writes)) { | 1488 | while (fi->writectr >= 0 && !list_empty(&fi->queued_writes)) { |
| 1478 | req = list_entry(fi->queued_writes.next, struct fuse_req, list); | 1489 | req = list_entry(fi->queued_writes.next, struct fuse_req, list); |
| 1479 | list_del_init(&req->list); | 1490 | list_del_init(&req->list); |
| 1480 | fuse_send_writepage(fc, req); | 1491 | fuse_send_writepage(fc, req, crop); |
| 1481 | } | 1492 | } |
| 1482 | } | 1493 | } |
| 1483 | 1494 | ||
| @@ -1488,12 +1499,62 @@ static void fuse_writepage_end(struct fuse_conn *fc, struct fuse_req *req) | |||
| 1488 | 1499 | ||
| 1489 | mapping_set_error(inode->i_mapping, req->out.h.error); | 1500 | mapping_set_error(inode->i_mapping, req->out.h.error); |
| 1490 | spin_lock(&fc->lock); | 1501 | spin_lock(&fc->lock); |
| 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; | ||
| 1505 | struct fuse_req *next = req->misc.write.next; | ||
| 1506 | req->misc.write.next = next->misc.write.next; | ||
| 1507 | next->misc.write.next = NULL; | ||
| 1508 | next->ff = fuse_file_get(req->ff); | ||
| 1509 | list_add(&next->writepages_entry, &fi->writepages); | ||
| 1510 | |||
| 1511 | /* | ||
| 1512 | * Skip fuse_flush_writepages() to make it easy to crop requests | ||
| 1513 | * based on primary request size. | ||
| 1514 | * | ||
| 1515 | * 1st case (trivial): there are no concurrent activities using | ||
| 1516 | * fuse_set/release_nowrite. Then we're on safe side because | ||
| 1517 | * fuse_flush_writepages() would call fuse_send_writepage() | ||
| 1518 | * anyway. | ||
| 1519 | * | ||
| 1520 | * 2nd case: someone called fuse_set_nowrite and it is waiting | ||
| 1521 | * now for completion of all in-flight requests. This happens | ||
| 1522 | * rarely and no more than once per page, so this should be | ||
| 1523 | * okay. | ||
| 1524 | * | ||
| 1525 | * 3rd case: someone (e.g. fuse_do_setattr()) is in the middle | ||
| 1526 | * of fuse_set_nowrite..fuse_release_nowrite section. The fact | ||
| 1527 | * that fuse_set_nowrite returned implies that all in-flight | ||
| 1528 | * requests were completed along with all of their secondary | ||
| 1529 | * requests. Further primary requests are blocked by negative | ||
| 1530 | * writectr. Hence there cannot be any in-flight requests and | ||
| 1531 | * no invocations of fuse_writepage_end() while we're in | ||
| 1532 | * fuse_set_nowrite..fuse_release_nowrite section. | ||
| 1533 | */ | ||
| 1534 | fuse_send_writepage(fc, next, inarg->offset + inarg->size); | ||
| 1535 | } | ||
| 1491 | fi->writectr--; | 1536 | fi->writectr--; |
| 1492 | fuse_writepage_finish(fc, req); | 1537 | fuse_writepage_finish(fc, req); |
| 1493 | spin_unlock(&fc->lock); | 1538 | spin_unlock(&fc->lock); |
| 1494 | fuse_writepage_free(fc, req); | 1539 | fuse_writepage_free(fc, req); |
| 1495 | } | 1540 | } |
| 1496 | 1541 | ||
| 1542 | static struct fuse_file *fuse_write_file_get(struct fuse_conn *fc, | ||
| 1543 | struct fuse_inode *fi) | ||
| 1544 | { | ||
| 1545 | struct fuse_file *ff = NULL; | ||
| 1546 | |||
| 1547 | spin_lock(&fc->lock); | ||
| 1548 | if (!WARN_ON(list_empty(&fi->write_files))) { | ||
| 1549 | ff = list_entry(fi->write_files.next, struct fuse_file, | ||
| 1550 | write_entry); | ||
| 1551 | fuse_file_get(ff); | ||
