aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ceph
diff options
context:
space:
mode:
authorYan, Zheng <zyan@redhat.com>2015-01-09 02:56:18 -0500
committerIlya Dryomov <idryomov@gmail.com>2015-02-19 05:31:38 -0500
commitc4d4a582c538e890f09c338bc3063c28dfdc9ae5 (patch)
tree2d6d7d75b857efcda89931866481057660dedaae /fs/ceph
parentd3383a8e37f802818cde4cb489bb0735db637cf0 (diff)
ceph: avoid block operation when !TASK_RUNNING (ceph_get_caps)
we should not do block operation in wait_event_interruptible()'s condition check function, but reading inline data can block. so move the read inline data code to ceph_get_caps() Signed-off-by: Yan, Zheng <zyan@redhat.com>
Diffstat (limited to 'fs/ceph')
-rw-r--r--fs/ceph/caps.c86
1 files changed, 42 insertions, 44 deletions
diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c
index 844b57cb52bd..8172775428a0 100644
--- a/fs/ceph/caps.c
+++ b/fs/ceph/caps.c
@@ -2072,17 +2072,16 @@ static void __take_cap_refs(struct ceph_inode_info *ci, int got)
2072 * requested from the MDS. 2072 * requested from the MDS.
2073 */ 2073 */
2074static int try_get_cap_refs(struct ceph_inode_info *ci, int need, int want, 2074static int try_get_cap_refs(struct ceph_inode_info *ci, int need, int want,
2075 loff_t endoff, int *got, struct page **pinned_page, 2075 loff_t endoff, int *got, int *check_max, int *err)
2076 int *check_max, int *err)
2077{ 2076{
2078 struct inode *inode = &ci->vfs_inode; 2077 struct inode *inode = &ci->vfs_inode;
2079 int ret = 0; 2078 int ret = 0;
2080 int have, implemented, _got = 0; 2079 int have, implemented;
2081 int file_wanted; 2080 int file_wanted;
2082 2081
2083 dout("get_cap_refs %p need %s want %s\n", inode, 2082 dout("get_cap_refs %p need %s want %s\n", inode,
2084 ceph_cap_string(need), ceph_cap_string(want)); 2083 ceph_cap_string(need), ceph_cap_string(want));
2085again: 2084
2086 spin_lock(&ci->i_ceph_lock); 2085 spin_lock(&ci->i_ceph_lock);
2087 2086
2088 /* make sure file is actually open */ 2087 /* make sure file is actually open */
@@ -2137,8 +2136,8 @@ again:
2137 inode, ceph_cap_string(have), ceph_cap_string(not), 2136 inode, ceph_cap_string(have), ceph_cap_string(not),
2138 ceph_cap_string(revoking)); 2137 ceph_cap_string(revoking));
2139 if ((revoking & not) == 0) { 2138 if ((revoking & not) == 0) {
2140 _got = need | (have & want); 2139 *got = need | (have & want);
2141 __take_cap_refs(ci, _got); 2140 __take_cap_refs(ci, *got);
2142 ret = 1; 2141 ret = 1;
2143 } 2142 }
2144 } else { 2143 } else {
@@ -2163,39 +2162,8 @@ again:
2163out_unlock: 2162out_unlock:
2164 spin_unlock(&ci->i_ceph_lock); 2163 spin_unlock(&ci->i_ceph_lock);
2165 2164
2166 if (ci->i_inline_version != CEPH_INLINE_NONE &&
2167 (_got & (CEPH_CAP_FILE_CACHE|CEPH_CAP_FILE_LAZYIO)) &&
2168 i_size_read(inode) > 0) {
2169 int ret1;
2170 struct page *page = find_get_page(inode->i_mapping, 0);
2171 if (page) {
2172 if (PageUptodate(page)) {
2173 *pinned_page = page;
2174 goto out;
2175 }
2176 page_cache_release(page);
2177 }
2178 /*
2179 * drop cap refs first because getattr while holding
2180 * caps refs can cause deadlock.
2181 */
2182 ceph_put_cap_refs(ci, _got);
2183 _got = 0;
2184
2185 /* getattr request will bring inline data into page cache */
2186 ret1 = __ceph_do_getattr(inode, NULL,
2187 CEPH_STAT_CAP_INLINE_DATA, true);
2188 if (ret1 >= 0) {
2189 ret = 0;
2190 goto again;
2191 }
2192 *err = ret1;
2193 ret = 1;
2194 }
2195out:
2196 dout("get_cap_refs %p ret %d got %s\n", inode, 2165 dout("get_cap_refs %p ret %d got %s\n", inode,
2197 ret, ceph_cap_string(_got)); 2166 ret, ceph_cap_string(*got));
2198 *got = _got;
2199 return ret; 2167 return ret;
2200} 2168}
2201 2169
@@ -2235,22 +2203,52 @@ static void check_max_size(struct inode *inode, loff_t endoff)
2235int ceph_get_caps(struct ceph_inode_info *ci, int need, int want, 2203int ceph_get_caps(struct ceph_inode_info *ci, int need, int want,
2236 loff_t endoff, int *got, struct page **pinned_page) 2204 loff_t endoff, int *got, struct page **pinned_page)
2237{ 2205{
2238 int check_max, ret, err; 2206 int _got, check_max, ret, err = 0;
2239 2207
2240retry: 2208retry:
2241 if (endoff > 0) 2209 if (endoff > 0)
2242 check_max_size(&ci->vfs_inode, endoff); 2210 check_max_size(&ci->vfs_inode, endoff);
2211 _got = 0;
2243 check_max = 0; 2212 check_max = 0;
2244 err = 0;
2245 ret = wait_event_interruptible(ci->i_cap_wq, 2213 ret = wait_event_interruptible(ci->i_cap_wq,
2246 try_get_cap_refs(ci, need, want, endoff, 2214 try_get_cap_refs(ci, need, want, endoff,
2247 got, pinned_page, 2215 &_got, &check_max, &err));
2248 &check_max, &err));
2249 if (err) 2216 if (err)
2250 ret = err; 2217 ret = err;
2218 if (ret < 0)
2219 return ret;
2220
2251 if (check_max) 2221 if (check_max)
2252 goto retry; 2222 goto retry;
2253 return ret; 2223
2224 if (ci->i_inline_version != CEPH_INLINE_NONE &&
2225 (_got & (CEPH_CAP_FILE_CACHE|CEPH_CAP_FILE_LAZYIO)) &&
2226 i_size_read(&ci->vfs_inode) > 0) {
2227 struct page *page = find_get_page(ci->vfs_inode.i_mapping, 0);
2228 if (page) {
2229 if (PageUptodate(page)) {
2230 *pinned_page = page;
2231 goto out;
2232 }
2233 page_cache_release(page);
2234 }
2235 /*
2236 * drop cap refs first because getattr while holding
2237 * caps refs can cause deadlock.
2238 */
2239 ceph_put_cap_refs(ci, _got);
2240 _got = 0;
2241
2242 /* getattr request will bring inline data into page cache */
2243 ret = __ceph_do_getattr(&ci->vfs_inode, NULL,
2244 CEPH_STAT_CAP_INLINE_DATA, true);
2245 if (ret < 0)
2246 return ret;
2247 goto retry;
2248 }
2249out:
2250 *got = _got;
2251 return 0;
2254} 2252}
2255 2253
2256/* 2254/*