diff options
author | Yan, Zheng <zyan@redhat.com> | 2018-03-15 23:22:29 -0400 |
---|---|---|
committer | Ilya Dryomov <idryomov@gmail.com> | 2018-03-30 05:17:48 -0400 |
commit | 85784f9395987a422fa04263e7c0fb13da11eb5c (patch) | |
tree | f8f998acb306c25992468d0a52e9082616b37ea5 | |
parent | 3eb2ce825ea1ad89d20f7a3b5780df850e4be274 (diff) |
ceph: only dirty ITER_IOVEC pages for direct read
If a page is already locked, attempting to dirty it leads to a deadlock
in lock_page(). This is what currently happens to ITER_BVEC pages when
a dio-enabled loop device is backed by ceph:
$ losetup --direct-io /dev/loop0 /mnt/cephfs/img
$ xfs_io -c 'pread 0 4k' /dev/loop0
Follow other file systems and only dirty ITER_IOVEC pages.
Cc: stable@kernel.org
Signed-off-by: "Yan, Zheng" <zyan@redhat.com>
Reviewed-by: Ilya Dryomov <idryomov@gmail.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
-rw-r--r-- | fs/ceph/file.c | 9 |
1 files changed, 6 insertions, 3 deletions
diff --git a/fs/ceph/file.c b/fs/ceph/file.c index 6639926eed4e..b67eec3532a1 100644 --- a/fs/ceph/file.c +++ b/fs/ceph/file.c | |||
@@ -640,7 +640,8 @@ static ssize_t ceph_sync_read(struct kiocb *iocb, struct iov_iter *to, | |||
640 | struct ceph_aio_request { | 640 | struct ceph_aio_request { |
641 | struct kiocb *iocb; | 641 | struct kiocb *iocb; |
642 | size_t total_len; | 642 | size_t total_len; |
643 | int write; | 643 | bool write; |
644 | bool should_dirty; | ||
644 | int error; | 645 | int error; |
645 | struct list_head osd_reqs; | 646 | struct list_head osd_reqs; |
646 | unsigned num_reqs; | 647 | unsigned num_reqs; |
@@ -750,7 +751,7 @@ static void ceph_aio_complete_req(struct ceph_osd_request *req) | |||
750 | } | 751 | } |
751 | } | 752 | } |
752 | 753 | ||
753 | ceph_put_page_vector(osd_data->pages, num_pages, !aio_req->write); | 754 | ceph_put_page_vector(osd_data->pages, num_pages, aio_req->should_dirty); |
754 | ceph_osdc_put_request(req); | 755 | ceph_osdc_put_request(req); |
755 | 756 | ||
756 | if (rc < 0) | 757 | if (rc < 0) |
@@ -847,6 +848,7 @@ ceph_direct_read_write(struct kiocb *iocb, struct iov_iter *iter, | |||
847 | size_t count = iov_iter_count(iter); | 848 | size_t count = iov_iter_count(iter); |
848 | loff_t pos = iocb->ki_pos; | 849 | loff_t pos = iocb->ki_pos; |
849 | bool write = iov_iter_rw(iter) == WRITE; | 850 | bool write = iov_iter_rw(iter) == WRITE; |
851 | bool should_dirty = !write && iter_is_iovec(iter); | ||
850 | 852 | ||
851 | if (write && ceph_snap(file_inode(file)) != CEPH_NOSNAP) | 853 | if (write && ceph_snap(file_inode(file)) != CEPH_NOSNAP) |
852 | return -EROFS; | 854 | return -EROFS; |
@@ -914,6 +916,7 @@ ceph_direct_read_write(struct kiocb *iocb, struct iov_iter *iter, | |||
914 | if (aio_req) { | 916 | if (aio_req) { |
915 | aio_req->iocb = iocb; | 917 | aio_req->iocb = iocb; |
916 | aio_req->write = write; | 918 | aio_req->write = write; |
919 | aio_req->should_dirty = should_dirty; | ||
917 | INIT_LIST_HEAD(&aio_req->osd_reqs); | 920 | INIT_LIST_HEAD(&aio_req->osd_reqs); |
918 | if (write) { | 921 | if (write) { |
919 | aio_req->mtime = mtime; | 922 | aio_req->mtime = mtime; |
@@ -971,7 +974,7 @@ ceph_direct_read_write(struct kiocb *iocb, struct iov_iter *iter, | |||
971 | len = ret; | 974 | len = ret; |
972 | } | 975 | } |
973 | 976 | ||
974 | ceph_put_page_vector(pages, num_pages, !write); | 977 | ceph_put_page_vector(pages, num_pages, should_dirty); |
975 | 978 | ||
976 | ceph_osdc_put_request(req); | 979 | ceph_osdc_put_request(req); |
977 | if (ret < 0) | 980 | if (ret < 0) |