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 /fs/ceph | |
| 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>
Diffstat (limited to 'fs/ceph')
| -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) |
