diff options
author | Yan, Zheng <zheng.z.yan@intel.com> | 2013-10-31 04:44:14 -0400 |
---|---|---|
committer | Yan, Zheng <zheng.z.yan@intel.com> | 2014-01-21 00:29:32 -0500 |
commit | 4fe59789adc93b2573b0417ac93136805521902e (patch) | |
tree | eab5cc55b2785c1617ba21478a82f47dd2663ad4 /fs | |
parent | fc12c80aa57ee90385dc90e4263ec1a66200ba76 (diff) |
ceph: handle cap export race in try_flush_caps()
auth cap may change after releasing the i_ceph_lock
Signed-off-by: Yan, Zheng <zheng.z.yan@intel.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/ceph/caps.c | 16 |
1 files changed, 8 insertions, 8 deletions
diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index 80dad0d491a3..101209930d5c 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c | |||
@@ -1735,13 +1735,12 @@ ack: | |||
1735 | /* | 1735 | /* |
1736 | * Try to flush dirty caps back to the auth mds. | 1736 | * Try to flush dirty caps back to the auth mds. |
1737 | */ | 1737 | */ |
1738 | static int try_flush_caps(struct inode *inode, struct ceph_mds_session *session, | 1738 | static int try_flush_caps(struct inode *inode, unsigned *flush_tid) |
1739 | unsigned *flush_tid) | ||
1740 | { | 1739 | { |
1741 | struct ceph_mds_client *mdsc = ceph_sb_to_client(inode->i_sb)->mdsc; | 1740 | struct ceph_mds_client *mdsc = ceph_sb_to_client(inode->i_sb)->mdsc; |
1742 | struct ceph_inode_info *ci = ceph_inode(inode); | 1741 | struct ceph_inode_info *ci = ceph_inode(inode); |
1743 | int unlock_session = session ? 0 : 1; | ||
1744 | int flushing = 0; | 1742 | int flushing = 0; |
1743 | struct ceph_mds_session *session = NULL; | ||
1745 | 1744 | ||
1746 | retry: | 1745 | retry: |
1747 | spin_lock(&ci->i_ceph_lock); | 1746 | spin_lock(&ci->i_ceph_lock); |
@@ -1755,13 +1754,14 @@ retry: | |||
1755 | int want = __ceph_caps_wanted(ci); | 1754 | int want = __ceph_caps_wanted(ci); |
1756 | int delayed; | 1755 | int delayed; |
1757 | 1756 | ||
1758 | if (!session) { | 1757 | if (!session || session != cap->session) { |
1759 | spin_unlock(&ci->i_ceph_lock); | 1758 | spin_unlock(&ci->i_ceph_lock); |
1759 | if (session) | ||
1760 | mutex_unlock(&session->s_mutex); | ||
1760 | session = cap->session; | 1761 | session = cap->session; |
1761 | mutex_lock(&session->s_mutex); | 1762 | mutex_lock(&session->s_mutex); |
1762 | goto retry; | 1763 | goto retry; |
1763 | } | 1764 | } |
1764 | BUG_ON(session != cap->session); | ||
1765 | if (cap->session->s_state < CEPH_MDS_SESSION_OPEN) | 1765 | if (cap->session->s_state < CEPH_MDS_SESSION_OPEN) |
1766 | goto out; | 1766 | goto out; |
1767 | 1767 | ||
@@ -1780,7 +1780,7 @@ retry: | |||
1780 | out: | 1780 | out: |
1781 | spin_unlock(&ci->i_ceph_lock); | 1781 | spin_unlock(&ci->i_ceph_lock); |
1782 | out_unlocked: | 1782 | out_unlocked: |
1783 | if (session && unlock_session) | 1783 | if (session) |
1784 | mutex_unlock(&session->s_mutex); | 1784 | mutex_unlock(&session->s_mutex); |
1785 | return flushing; | 1785 | return flushing; |
1786 | } | 1786 | } |
@@ -1865,7 +1865,7 @@ int ceph_fsync(struct file *file, loff_t start, loff_t end, int datasync) | |||
1865 | return ret; | 1865 | return ret; |
1866 | mutex_lock(&inode->i_mutex); | 1866 | mutex_lock(&inode->i_mutex); |
1867 | 1867 | ||
1868 | dirty = try_flush_caps(inode, NULL, &flush_tid); | 1868 | dirty = try_flush_caps(inode, &flush_tid); |
1869 | dout("fsync dirty caps are %s\n", ceph_cap_string(dirty)); | 1869 | dout("fsync dirty caps are %s\n", ceph_cap_string(dirty)); |
1870 | 1870 | ||
1871 | /* | 1871 | /* |
@@ -1900,7 +1900,7 @@ int ceph_write_inode(struct inode *inode, struct writeback_control *wbc) | |||
1900 | 1900 | ||
1901 | dout("write_inode %p wait=%d\n", inode, wait); | 1901 | dout("write_inode %p wait=%d\n", inode, wait); |
1902 | if (wait) { | 1902 | if (wait) { |
1903 | dirty = try_flush_caps(inode, NULL, &flush_tid); | 1903 | dirty = try_flush_caps(inode, &flush_tid); |
1904 | if (dirty) | 1904 | if (dirty) |
1905 | err = wait_event_interruptible(ci->i_cap_wq, | 1905 | err = wait_event_interruptible(ci->i_cap_wq, |
1906 | caps_are_flushed(inode, flush_tid)); | 1906 | caps_are_flushed(inode, flush_tid)); |