aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ceph
diff options
context:
space:
mode:
authorYan, Zheng <zyan@redhat.com>2015-12-23 19:44:20 -0500
committerIlya Dryomov <idryomov@gmail.com>2016-01-21 13:36:08 -0500
commit5be0389dac662995eade757ec678931f0be23d33 (patch)
tree89951af8adafe581682591bf755006a60517edb5 /fs/ceph
parentc8fe9b17d055fe80e1a1591f5900ce41fbf6b796 (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.c90
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
561struct ceph_aio_work {
562 struct work_struct work;
563 struct ceph_osd_request *req;
564};
565
566static void ceph_aio_retry_work(struct work_struct *work);
567
560static void ceph_aio_complete(struct inode *inode, 568static 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
673static 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);
726out:
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 }