diff options
author | Yan, Zheng <zyan@redhat.com> | 2015-12-23 19:44:20 -0500 |
---|---|---|
committer | Ilya Dryomov <idryomov@gmail.com> | 2016-01-21 13:36:08 -0500 |
commit | 5be0389dac662995eade757ec678931f0be23d33 (patch) | |
tree | 89951af8adafe581682591bf755006a60517edb5 /fs/ceph | |
parent | c8fe9b17d055fe80e1a1591f5900ce41fbf6b796 (diff) |
ceph: re-send AIO write request when getting -EOLDSNAP error
When receiving -EOLDSNAP from OSD, we need to re-send corresponding
write request. Due to locking issue, we can send new request inside
another OSD request's complete callback. So we use worker to re-send
request for AIO write.
Signed-off-by: Yan, Zheng <zyan@redhat.com>
Diffstat (limited to 'fs/ceph')
-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 | } |