diff options
Diffstat (limited to 'fs/ceph/file.c')
-rw-r--r-- | fs/ceph/file.c | 79 |
1 files changed, 33 insertions, 46 deletions
diff --git a/fs/ceph/file.c b/fs/ceph/file.c index 5840d2aaed15..e51558fca3a3 100644 --- a/fs/ceph/file.c +++ b/fs/ceph/file.c | |||
@@ -712,63 +712,53 @@ static ssize_t ceph_aio_write(struct kiocb *iocb, const struct iovec *iov, | |||
712 | struct ceph_osd_client *osdc = | 712 | struct ceph_osd_client *osdc = |
713 | &ceph_sb_to_client(inode->i_sb)->client->osdc; | 713 | &ceph_sb_to_client(inode->i_sb)->client->osdc; |
714 | loff_t endoff = pos + iov->iov_len; | 714 | loff_t endoff = pos + iov->iov_len; |
715 | int want, got = 0; | 715 | int got = 0; |
716 | int ret, err; | 716 | int ret, err, written; |
717 | 717 | ||
718 | if (ceph_snap(inode) != CEPH_NOSNAP) | 718 | if (ceph_snap(inode) != CEPH_NOSNAP) |
719 | return -EROFS; | 719 | return -EROFS; |
720 | 720 | ||
721 | retry_snap: | 721 | retry_snap: |
722 | written = 0; | ||
722 | if (ceph_osdmap_flag(osdc->osdmap, CEPH_OSDMAP_FULL)) | 723 | if (ceph_osdmap_flag(osdc->osdmap, CEPH_OSDMAP_FULL)) |
723 | return -ENOSPC; | 724 | return -ENOSPC; |
724 | __ceph_do_pending_vmtruncate(inode); | 725 | __ceph_do_pending_vmtruncate(inode); |
725 | dout("aio_write %p %llx.%llx %llu~%u getting caps. i_size %llu\n", | ||
726 | inode, ceph_vinop(inode), pos, (unsigned)iov->iov_len, | ||
727 | inode->i_size); | ||
728 | if (fi->fmode & CEPH_FILE_MODE_LAZY) | ||
729 | want = CEPH_CAP_FILE_BUFFER | CEPH_CAP_FILE_LAZYIO; | ||
730 | else | ||
731 | want = CEPH_CAP_FILE_BUFFER; | ||
732 | ret = ceph_get_caps(ci, CEPH_CAP_FILE_WR, want, &got, endoff); | ||
733 | if (ret < 0) | ||
734 | goto out_put; | ||
735 | |||
736 | dout("aio_write %p %llx.%llx %llu~%u got cap refs on %s\n", | ||
737 | inode, ceph_vinop(inode), pos, (unsigned)iov->iov_len, | ||
738 | ceph_cap_string(got)); | ||
739 | |||
740 | if ((got & (CEPH_CAP_FILE_BUFFER|CEPH_CAP_FILE_LAZYIO)) == 0 || | ||
741 | (iocb->ki_filp->f_flags & O_DIRECT) || | ||
742 | (inode->i_sb->s_flags & MS_SYNCHRONOUS) || | ||
743 | (fi->flags & CEPH_F_SYNC)) { | ||
744 | ret = ceph_sync_write(file, iov->iov_base, iov->iov_len, | ||
745 | &iocb->ki_pos); | ||
746 | } else { | ||
747 | /* | ||
748 | * buffered write; drop Fw early to avoid slow | ||
749 | * revocation if we get stuck on balance_dirty_pages | ||
750 | */ | ||
751 | int dirty; | ||
752 | |||
753 | spin_lock(&ci->i_ceph_lock); | ||
754 | dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_FILE_WR); | ||
755 | spin_unlock(&ci->i_ceph_lock); | ||
756 | ceph_put_cap_refs(ci, got); | ||
757 | 726 | ||
727 | /* | ||
728 | * try to do a buffered write. if we don't have sufficient | ||
729 | * caps, we'll get -EAGAIN from generic_file_aio_write, or a | ||
730 | * short write if we only get caps for some pages. | ||
731 | */ | ||
732 | if (!(iocb->ki_filp->f_flags & O_DIRECT) && | ||
733 | !(inode->i_sb->s_flags & MS_SYNCHRONOUS) && | ||
734 | !(fi->flags & CEPH_F_SYNC)) { | ||
758 | ret = generic_file_aio_write(iocb, iov, nr_segs, pos); | 735 | ret = generic_file_aio_write(iocb, iov, nr_segs, pos); |
736 | if (ret >= 0) | ||
737 | written = ret; | ||
738 | |||
759 | if ((ret >= 0 || ret == -EIOCBQUEUED) && | 739 | if ((ret >= 0 || ret == -EIOCBQUEUED) && |
760 | ((file->f_flags & O_SYNC) || IS_SYNC(file->f_mapping->host) | 740 | ((file->f_flags & O_SYNC) || IS_SYNC(file->f_mapping->host) |
761 | || ceph_osdmap_flag(osdc->osdmap, CEPH_OSDMAP_NEARFULL))) { | 741 | || ceph_osdmap_flag(osdc->osdmap, CEPH_OSDMAP_NEARFULL))) { |
762 | err = vfs_fsync_range(file, pos, pos + ret - 1, 1); | 742 | err = vfs_fsync_range(file, pos, pos + written - 1, 1); |
763 | if (err < 0) | 743 | if (err < 0) |
764 | ret = err; | 744 | ret = err; |
765 | } | 745 | } |
746 | if ((ret < 0 && ret != -EAGAIN) || pos + written >= endoff) | ||
747 | goto out; | ||
748 | } | ||
766 | 749 | ||
767 | if (dirty) | 750 | dout("aio_write %p %llx.%llx %llu~%u getting caps. i_size %llu\n", |
768 | __mark_inode_dirty(inode, dirty); | 751 | inode, ceph_vinop(inode), pos + written, |
752 | (unsigned)iov->iov_len - written, inode->i_size); | ||
753 | ret = ceph_get_caps(ci, CEPH_CAP_FILE_WR, 0, &got, endoff); | ||
754 | if (ret < 0) | ||
769 | goto out; | 755 | goto out; |
770 | } | ||
771 | 756 | ||
757 | dout("aio_write %p %llx.%llx %llu~%u got cap refs on %s\n", | ||
758 | inode, ceph_vinop(inode), pos + written, | ||
759 | (unsigned)iov->iov_len - written, ceph_cap_string(got)); | ||
760 | ret = ceph_sync_write(file, iov->iov_base + written, | ||
761 | iov->iov_len - written, &iocb->ki_pos); | ||
772 | if (ret >= 0) { | 762 | if (ret >= 0) { |
773 | int dirty; | 763 | int dirty; |
774 | spin_lock(&ci->i_ceph_lock); | 764 | spin_lock(&ci->i_ceph_lock); |
@@ -777,13 +767,10 @@ retry_snap: | |||
777 | if (dirty) | 767 | if (dirty) |
778 | __mark_inode_dirty(inode, dirty); | 768 | __mark_inode_dirty(inode, dirty); |
779 | } | 769 | } |
780 | |||
781 | out_put: | ||
782 | dout("aio_write %p %llx.%llx %llu~%u dropping cap refs on %s\n", | 770 | dout("aio_write %p %llx.%llx %llu~%u dropping cap refs on %s\n", |
783 | inode, ceph_vinop(inode), pos, (unsigned)iov->iov_len, | 771 | inode, ceph_vinop(inode), pos + written, |
784 | ceph_cap_string(got)); | 772 | (unsigned)iov->iov_len - written, ceph_cap_string(got)); |
785 | ceph_put_cap_refs(ci, got); | 773 | ceph_put_cap_refs(ci, got); |
786 | |||
787 | out: | 774 | out: |
788 | if (ret == -EOLDSNAPC) { | 775 | if (ret == -EOLDSNAPC) { |
789 | dout("aio_write %p %llx.%llx %llu~%u got EOLDSNAPC, retrying\n", | 776 | dout("aio_write %p %llx.%llx %llu~%u got EOLDSNAPC, retrying\n", |
@@ -797,7 +784,7 @@ out: | |||
797 | /* | 784 | /* |
798 | * llseek. be sure to verify file size on SEEK_END. | 785 | * llseek. be sure to verify file size on SEEK_END. |
799 | */ | 786 | */ |
800 | static loff_t ceph_llseek(struct file *file, loff_t offset, int origin) | 787 | static loff_t ceph_llseek(struct file *file, loff_t offset, int whence) |
801 | { | 788 | { |
802 | struct inode *inode = file->f_mapping->host; | 789 | struct inode *inode = file->f_mapping->host; |
803 | int ret; | 790 | int ret; |
@@ -805,7 +792,7 @@ static loff_t ceph_llseek(struct file *file, loff_t offset, int origin) | |||
805 | mutex_lock(&inode->i_mutex); | 792 | mutex_lock(&inode->i_mutex); |
806 | __ceph_do_pending_vmtruncate(inode); | 793 | __ceph_do_pending_vmtruncate(inode); |
807 | 794 | ||
808 | if (origin == SEEK_END || origin == SEEK_DATA || origin == SEEK_HOLE) { | 795 | if (whence == SEEK_END || whence == SEEK_DATA || whence == SEEK_HOLE) { |
809 | ret = ceph_do_getattr(inode, CEPH_STAT_CAP_SIZE); | 796 | ret = ceph_do_getattr(inode, CEPH_STAT_CAP_SIZE); |
810 | if (ret < 0) { | 797 | if (ret < 0) { |
811 | offset = ret; | 798 | offset = ret; |
@@ -813,7 +800,7 @@ static loff_t ceph_llseek(struct file *file, loff_t offset, int origin) | |||
813 | } | 800 | } |
814 | } | 801 | } |
815 | 802 | ||
816 | switch (origin) { | 803 | switch (whence) { |
817 | case SEEK_END: | 804 | case SEEK_END: |
818 | offset += inode->i_size; | 805 | offset += inode->i_size; |
819 | break; | 806 | break; |