diff options
| -rw-r--r-- | fs/ceph/file.c | 90 |
1 files changed, 86 insertions, 4 deletions
diff --git a/fs/ceph/file.c b/fs/ceph/file.c index 8e924b7dd498..41c2267b4b7e 100644 --- a/fs/ceph/file.c +++ b/fs/ceph/file.c | |||
| @@ -554,9 +554,17 @@ struct ceph_aio_request { | |||
| 554 | struct list_head osd_reqs; | 554 | struct list_head osd_reqs; |
| 555 | unsigned num_reqs; | 555 | unsigned num_reqs; |
| 556 | atomic_t pending_reqs; | 556 | atomic_t pending_reqs; |
| 557 | struct timespec mtime; | ||
| 557 | struct ceph_cap_flush *prealloc_cf; | 558 | struct ceph_cap_flush *prealloc_cf; |
| 558 | }; | 559 | }; |
| 559 | 560 | ||
| 561 | struct ceph_aio_work { | ||
| 562 | struct work_struct work; | ||
| 563 | struct ceph_osd_request *req; | ||
| 564 | }; | ||
| 565 | |||
| 566 | static void ceph_aio_retry_work(struct work_struct *work); | ||
| 567 | |||
| 560 | static void ceph_aio_complete(struct inode *inode, | 568 | static void ceph_aio_complete(struct inode *inode, |
| 561 | struct ceph_aio_request *aio_req) | 569 | struct ceph_aio_request *aio_req) |
| 562 | { | 570 | { |
| @@ -614,10 +622,19 @@ static void ceph_aio_complete_req(struct ceph_osd_request *req, | |||
| 614 | inode, rc, osd_data->length); | 622 | inode, rc, osd_data->length); |
| 615 | 623 | ||
| 616 | if (rc == -EOLDSNAPC) { | 624 | if (rc == -EOLDSNAPC) { |
| 617 | BUG_ON(1); | 625 | struct ceph_aio_work *aio_work; |
| 618 | } | 626 | BUG_ON(!aio_req->write); |
| 619 | 627 | ||
| 620 | if (!aio_req->write) { | 628 | aio_work = kmalloc(sizeof(*aio_work), GFP_NOFS); |
| 629 | if (aio_work) { | ||
| 630 | INIT_WORK(&aio_work->work, ceph_aio_retry_work); | ||
| 631 | aio_work->req = req; | ||
| 632 | queue_work(ceph_inode_to_client(inode)->wb_wq, | ||
| 633 | &aio_work->work); | ||
| 634 | return; | ||
| 635 | } | ||
| 636 | rc = -ENOMEM; | ||
| 637 | } else if (!aio_req->write) { | ||
| 621 | if (rc == -ENOENT) | 638 | if (rc == -ENOENT) |
| 622 | rc = 0; | 639 | rc = 0; |
| 623 | if (rc >= 0 && osd_data->length > rc) { | 640 | if (rc >= 0 && osd_data->length > rc) { |
| @@ -653,6 +670,69 @@ static void ceph_aio_complete_req(struct ceph_osd_request *req, | |||
| 653 | return; | 670 | return; |
| 654 | } | 671 | } |
| 655 | 672 | ||
| 673 | static void ceph_aio_retry_work(struct work_struct *work) | ||
| 674 | { | ||
| 675 | struct ceph_aio_work *aio_work = | ||
| 676 | container_of(work, struct ceph_aio_work, work); | ||
| 677 | struct ceph_osd_request *orig_req = aio_work->req; | ||
| 678 | struct ceph_aio_request *aio_req = orig_req->r_priv; | ||
| 679 | struct inode *inode = orig_req->r_inode; | ||
| 680 | struct ceph_inode_info *ci = ceph_inode(inode); | ||
| 681 | struct ceph_snap_context *snapc; | ||
| 682 | struct ceph_osd_request *req; | ||
| 683 | int ret; | ||
| 684 | |||
| 685 | spin_lock(&ci->i_ceph_lock); | ||
| 686 | if (__ceph_have_pending_cap_snap(ci)) { | ||
| 687 | struct ceph_cap_snap *capsnap = | ||
| 688 | list_last_entry(&ci->i_cap_snaps, | ||
| 689 | struct ceph_cap_snap, | ||
| 690 | ci_item); | ||
| 691 | snapc = ceph_get_snap_context(capsnap->context); | ||
| 692 | } else { | ||
| 693 | BUG_ON(!ci->i_head_snapc); | ||
| 694 | snapc = ceph_get_snap_context(ci->i_head_snapc); | ||
| 695 | } | ||
| 696 | spin_unlock(&ci->i_ceph_lock); | ||
| 697 | |||
| 698 | req = ceph_osdc_alloc_request(orig_req->r_osdc, snapc, 2, | ||
| 699 | false, GFP_NOFS); | ||
| 700 | if (IS_ERR(req)) { | ||
| 701 | ret = PTR_ERR(req); | ||
| 702 | req = orig_req; | ||
| 703 | goto out; | ||
| 704 | } | ||
| 705 | |||
| 706 | req->r_flags = CEPH_OSD_FLAG_ORDERSNAP | | ||
| 707 | CEPH_OSD_FLAG_ONDISK | | ||
| 708 | CEPH_OSD_FLAG_WRITE; | ||
| 709 | req->r_base_oloc = orig_req->r_base_oloc; | ||
| 710 | req->r_base_oid = orig_req->r_base_oid; | ||
| 711 | |||
| 712 | req->r_ops[0] = orig_req->r_ops[0]; | ||
| 713 | osd_req_op_init(req, 1, CEPH_OSD_OP_STARTSYNC, 0); | ||
| 714 | |||
| 715 | ceph_osdc_build_request(req, req->r_ops[0].extent.offset, | ||
| 716 | snapc, CEPH_NOSNAP, &aio_req->mtime); | ||
| 717 | |||
| 718 | ceph_put_snap_context(snapc); | ||
| 719 | ceph_osdc_put_request(orig_req); | ||
| 720 | |||
| 721 | req->r_callback = ceph_aio_complete_req; | ||
| 722 | req->r_inode = inode; | ||
| 723 | req->r_priv = aio_req; | ||
| 724 | |||
| 725 | ret = ceph_osdc_start_request(req->r_osdc, req, false); | ||
| 726 | out: | ||
| 727 | if (ret < 0) { | ||
| 728 | BUG_ON(ret == -EOLDSNAPC); | ||
| 729 | req->r_result = ret; | ||
| 730 | ceph_aio_complete_req(req, NULL); | ||
| 731 | } | ||
| 732 | |||
| 733 | kfree(aio_work); | ||
| 734 | } | ||
| 735 | |||
| 656 | /* | 736 | /* |
| 657 | * Write commit request unsafe callback, called to tell us when a | 737 | * Write commit request unsafe callback, called to tell us when a |
| 658 | * request is unsafe (that is, in flight--has been handed to the | 738 | * request is unsafe (that is, in flight--has been handed to the |
| @@ -772,6 +852,7 @@ ceph_direct_read_write(struct kiocb *iocb, struct iov_iter *iter, | |||
| 772 | aio_req->write = write; | 852 | aio_req->write = write; |
| 773 | INIT_LIST_HEAD(&aio_req->osd_reqs); | 853 | INIT_LIST_HEAD(&aio_req->osd_reqs); |
| 774 | if (write) { | 854 | if (write) { |
| 855 | aio_req->mtime = mtime; | ||
| 775 | swap(aio_req->prealloc_cf, *pcf); | 856 | swap(aio_req->prealloc_cf, *pcf); |
| 776 | } | 857 | } |
| 777 | } | 858 | } |
| @@ -867,6 +948,7 @@ ceph_direct_read_write(struct kiocb *iocb, struct iov_iter *iter, | |||
| 867 | ret = ceph_osdc_start_request(req->r_osdc, | 948 | ret = ceph_osdc_start_request(req->r_osdc, |
| 868 | req, false); | 949 | req, false); |
| 869 | if (ret < 0) { | 950 | if (ret < 0) { |
| 951 | BUG_ON(ret == -EOLDSNAPC); | ||
| 870 | req->r_result = ret; | 952 | req->r_result = ret; |
| 871 | ceph_aio_complete_req(req, NULL); | 953 | ceph_aio_complete_req(req, NULL); |
| 872 | } | 954 | } |
