diff options
author | Yan, Zheng <zyan@redhat.com> | 2015-01-09 02:56:18 -0500 |
---|---|---|
committer | Ilya Dryomov <idryomov@gmail.com> | 2015-02-19 05:31:38 -0500 |
commit | c4d4a582c538e890f09c338bc3063c28dfdc9ae5 (patch) | |
tree | 2d6d7d75b857efcda89931866481057660dedaae /fs/ceph | |
parent | d3383a8e37f802818cde4cb489bb0735db637cf0 (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.c | 86 |
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 | */ |
2074 | static int try_get_cap_refs(struct ceph_inode_info *ci, int need, int want, | 2074 | static 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)); |
2085 | again: | 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: | |||
2163 | out_unlock: | 2162 | out_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 | } | ||
2195 | out: | ||
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) | |||
2235 | int ceph_get_caps(struct ceph_inode_info *ci, int need, int want, | 2203 | int 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 | ||
2240 | retry: | 2208 | retry: |
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 | } | ||
2249 | out: | ||
2250 | *got = _got; | ||
2251 | return 0; | ||
2254 | } | 2252 | } |
2255 | 2253 | ||
2256 | /* | 2254 | /* |