diff options
Diffstat (limited to 'fs/ceph/caps.c')
-rw-r--r-- | fs/ceph/caps.c | 127 |
1 files changed, 74 insertions, 53 deletions
diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index b93c631c6c87..8172775428a0 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c | |||
@@ -577,7 +577,6 @@ void ceph_add_cap(struct inode *inode, | |||
577 | struct ceph_snap_realm *realm = ceph_lookup_snap_realm(mdsc, | 577 | struct ceph_snap_realm *realm = ceph_lookup_snap_realm(mdsc, |
578 | realmino); | 578 | realmino); |
579 | if (realm) { | 579 | if (realm) { |
580 | ceph_get_snap_realm(mdsc, realm); | ||
581 | spin_lock(&realm->inodes_with_caps_lock); | 580 | spin_lock(&realm->inodes_with_caps_lock); |
582 | ci->i_snap_realm = realm; | 581 | ci->i_snap_realm = realm; |
583 | list_add(&ci->i_snap_realm_item, | 582 | list_add(&ci->i_snap_realm_item, |
@@ -1451,8 +1450,8 @@ static int __mark_caps_flushing(struct inode *inode, | |||
1451 | spin_lock(&mdsc->cap_dirty_lock); | 1450 | spin_lock(&mdsc->cap_dirty_lock); |
1452 | list_del_init(&ci->i_dirty_item); | 1451 | list_del_init(&ci->i_dirty_item); |
1453 | 1452 | ||
1454 | ci->i_cap_flush_seq = ++mdsc->cap_flush_seq; | ||
1455 | if (list_empty(&ci->i_flushing_item)) { | 1453 | if (list_empty(&ci->i_flushing_item)) { |
1454 | ci->i_cap_flush_seq = ++mdsc->cap_flush_seq; | ||
1456 | list_add_tail(&ci->i_flushing_item, &session->s_cap_flushing); | 1455 | list_add_tail(&ci->i_flushing_item, &session->s_cap_flushing); |
1457 | mdsc->num_cap_flushing++; | 1456 | mdsc->num_cap_flushing++; |
1458 | dout(" inode %p now flushing seq %lld\n", inode, | 1457 | dout(" inode %p now flushing seq %lld\n", inode, |
@@ -2073,17 +2072,16 @@ static void __take_cap_refs(struct ceph_inode_info *ci, int got) | |||
2073 | * requested from the MDS. | 2072 | * requested from the MDS. |
2074 | */ | 2073 | */ |
2075 | 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, |
2076 | loff_t endoff, int *got, struct page **pinned_page, | 2075 | loff_t endoff, int *got, int *check_max, int *err) |
2077 | int *check_max, int *err) | ||
2078 | { | 2076 | { |
2079 | struct inode *inode = &ci->vfs_inode; | 2077 | struct inode *inode = &ci->vfs_inode; |
2080 | int ret = 0; | 2078 | int ret = 0; |
2081 | int have, implemented, _got = 0; | 2079 | int have, implemented; |
2082 | int file_wanted; | 2080 | int file_wanted; |
2083 | 2081 | ||
2084 | dout("get_cap_refs %p need %s want %s\n", inode, | 2082 | dout("get_cap_refs %p need %s want %s\n", inode, |
2085 | ceph_cap_string(need), ceph_cap_string(want)); | 2083 | ceph_cap_string(need), ceph_cap_string(want)); |
2086 | again: | 2084 | |
2087 | spin_lock(&ci->i_ceph_lock); | 2085 | spin_lock(&ci->i_ceph_lock); |
2088 | 2086 | ||
2089 | /* make sure file is actually open */ | 2087 | /* make sure file is actually open */ |
@@ -2138,50 +2136,34 @@ again: | |||
2138 | inode, ceph_cap_string(have), ceph_cap_string(not), | 2136 | inode, ceph_cap_string(have), ceph_cap_string(not), |
2139 | ceph_cap_string(revoking)); | 2137 | ceph_cap_string(revoking)); |
2140 | if ((revoking & not) == 0) { | 2138 | if ((revoking & not) == 0) { |
2141 | _got = need | (have & want); | 2139 | *got = need | (have & want); |
2142 | __take_cap_refs(ci, _got); | 2140 | __take_cap_refs(ci, *got); |
2143 | ret = 1; | 2141 | ret = 1; |
2144 | } | 2142 | } |
2145 | } else { | 2143 | } else { |
2144 | int session_readonly = false; | ||
2145 | if ((need & CEPH_CAP_FILE_WR) && ci->i_auth_cap) { | ||
2146 | struct ceph_mds_session *s = ci->i_auth_cap->session; | ||
2147 | spin_lock(&s->s_cap_lock); | ||
2148 | session_readonly = s->s_readonly; | ||
2149 | spin_unlock(&s->s_cap_lock); | ||
2150 | } | ||
2151 | if (session_readonly) { | ||
2152 | dout("get_cap_refs %p needed %s but mds%d readonly\n", | ||
2153 | inode, ceph_cap_string(need), ci->i_auth_cap->mds); | ||
2154 | *err = -EROFS; | ||
2155 | ret = 1; | ||
2156 | goto out_unlock; | ||
2157 | } | ||
2158 | |||
2146 | dout("get_cap_refs %p have %s needed %s\n", inode, | 2159 | dout("get_cap_refs %p have %s needed %s\n", inode, |
2147 | ceph_cap_string(have), ceph_cap_string(need)); | 2160 | ceph_cap_string(have), ceph_cap_string(need)); |
2148 | } | 2161 | } |
2149 | out_unlock: | 2162 | out_unlock: |
2150 | spin_unlock(&ci->i_ceph_lock); | 2163 | spin_unlock(&ci->i_ceph_lock); |
2151 | 2164 | ||
2152 | if (ci->i_inline_version != CEPH_INLINE_NONE && | ||
2153 | (_got & (CEPH_CAP_FILE_CACHE|CEPH_CAP_FILE_LAZYIO)) && | ||
2154 | i_size_read(inode) > 0) { | ||
2155 | int ret1; | ||
2156 | struct page *page = find_get_page(inode->i_mapping, 0); | ||
2157 | if (page) { | ||
2158 | if (PageUptodate(page)) { | ||
2159 | *pinned_page = page; | ||
2160 | goto out; | ||
2161 | } | ||
2162 | page_cache_release(page); | ||
2163 | } | ||
2164 | /* | ||
2165 | * drop cap refs first because getattr while holding | ||
2166 | * caps refs can cause deadlock. | ||
2167 | */ | ||
2168 | ceph_put_cap_refs(ci, _got); | ||
2169 | _got = 0; | ||
2170 | |||
2171 | /* getattr request will bring inline data into page cache */ | ||
2172 | ret1 = __ceph_do_getattr(inode, NULL, | ||
2173 | CEPH_STAT_CAP_INLINE_DATA, true); | ||
2174 | if (ret1 >= 0) { | ||
2175 | ret = 0; | ||
2176 | goto again; | ||
2177 | } | ||
2178 | *err = ret1; | ||
2179 | ret = 1; | ||
2180 | } | ||
2181 | out: | ||
2182 | dout("get_cap_refs %p ret %d got %s\n", inode, | 2165 | dout("get_cap_refs %p ret %d got %s\n", inode, |
2183 | ret, ceph_cap_string(_got)); | 2166 | ret, ceph_cap_string(*got)); |
2184 | *got = _got; | ||
2185 | return ret; | 2167 | return ret; |
2186 | } | 2168 | } |
2187 | 2169 | ||
@@ -2221,22 +2203,52 @@ static void check_max_size(struct inode *inode, loff_t endoff) | |||
2221 | 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, |
2222 | loff_t endoff, int *got, struct page **pinned_page) | 2204 | loff_t endoff, int *got, struct page **pinned_page) |
2223 | { | 2205 | { |
2224 | int check_max, ret, err; | 2206 | int _got, check_max, ret, err = 0; |
2225 | 2207 | ||
2226 | retry: | 2208 | retry: |
2227 | if (endoff > 0) | 2209 | if (endoff > 0) |
2228 | check_max_size(&ci->vfs_inode, endoff); | 2210 | check_max_size(&ci->vfs_inode, endoff); |
2211 | _got = 0; | ||
2229 | check_max = 0; | 2212 | check_max = 0; |
2230 | err = 0; | ||
2231 | ret = wait_event_interruptible(ci->i_cap_wq, | 2213 | ret = wait_event_interruptible(ci->i_cap_wq, |
2232 | try_get_cap_refs(ci, need, want, endoff, | 2214 | try_get_cap_refs(ci, need, want, endoff, |
2233 | got, pinned_page, | 2215 | &_got, &check_max, &err)); |
2234 | &check_max, &err)); | ||
2235 | if (err) | 2216 | if (err) |
2236 | ret = err; | 2217 | ret = err; |
2218 | if (ret < 0) | ||
2219 | return ret; | ||
2220 | |||
2237 | if (check_max) | 2221 | if (check_max) |
2238 | goto retry; | 2222 | goto retry; |
2239 | 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; | ||
2240 | } | 2252 | } |
2241 | 2253 | ||
2242 | /* | 2254 | /* |
@@ -2432,13 +2444,13 @@ static void invalidate_aliases(struct inode *inode) | |||
2432 | */ | 2444 | */ |
2433 | static void handle_cap_grant(struct ceph_mds_client *mdsc, | 2445 | static void handle_cap_grant(struct ceph_mds_client *mdsc, |
2434 | struct inode *inode, struct ceph_mds_caps *grant, | 2446 | struct inode *inode, struct ceph_mds_caps *grant, |
2435 | void *snaptrace, int snaptrace_len, | ||
2436 | u64 inline_version, | 2447 | u64 inline_version, |
2437 | void *inline_data, int inline_len, | 2448 | void *inline_data, int inline_len, |
2438 | struct ceph_buffer *xattr_buf, | 2449 | struct ceph_buffer *xattr_buf, |
2439 | struct ceph_mds_session *session, | 2450 | struct ceph_mds_session *session, |
2440 | struct ceph_cap *cap, int issued) | 2451 | struct ceph_cap *cap, int issued) |
2441 | __releases(ci->i_ceph_lock) | 2452 | __releases(ci->i_ceph_lock) |
2453 | __releases(mdsc->snap_rwsem) | ||
2442 | { | 2454 | { |
2443 | struct ceph_inode_info *ci = ceph_inode(inode); | 2455 | struct ceph_inode_info *ci = ceph_inode(inode); |
2444 | int mds = session->s_mds; | 2456 | int mds = session->s_mds; |
@@ -2639,10 +2651,6 @@ static void handle_cap_grant(struct ceph_mds_client *mdsc, | |||
2639 | spin_unlock(&ci->i_ceph_lock); | 2651 | spin_unlock(&ci->i_ceph_lock); |
2640 | 2652 | ||
2641 | if (le32_to_cpu(grant->op) == CEPH_CAP_OP_IMPORT) { | 2653 | if (le32_to_cpu(grant->op) == CEPH_CAP_OP_IMPORT) { |
2642 | down_write(&mdsc->snap_rwsem); | ||
2643 | ceph_update_snap_trace(mdsc, snaptrace, | ||
2644 | snaptrace + snaptrace_len, false); | ||
2645 | downgrade_write(&mdsc->snap_rwsem); | ||
2646 | kick_flushing_inode_caps(mdsc, session, inode); | 2654 | kick_flushing_inode_caps(mdsc, session, inode); |
2647 | up_read(&mdsc->snap_rwsem); | 2655 | up_read(&mdsc->snap_rwsem); |
2648 | if (newcaps & ~issued) | 2656 | if (newcaps & ~issued) |
@@ -3052,6 +3060,7 @@ void ceph_handle_caps(struct ceph_mds_session *session, | |||
3052 | struct ceph_cap *cap; | 3060 | struct ceph_cap *cap; |
3053 | struct ceph_mds_caps *h; | 3061 | struct ceph_mds_caps *h; |
3054 | struct ceph_mds_cap_peer *peer = NULL; | 3062 | struct ceph_mds_cap_peer *peer = NULL; |
3063 | struct ceph_snap_realm *realm; | ||
3055 | int mds = session->s_mds; | 3064 | int mds = session->s_mds; |
3056 | int op, issued; | 3065 | int op, issued; |
3057 | u32 seq, mseq; | 3066 | u32 seq, mseq; |
@@ -3153,11 +3162,23 @@ void ceph_handle_caps(struct ceph_mds_session *session, | |||
3153 | goto done_unlocked; | 3162 | goto done_unlocked; |
3154 | 3163 | ||
3155 | case CEPH_CAP_OP_IMPORT: | 3164 | case CEPH_CAP_OP_IMPORT: |
3165 | realm = NULL; | ||
3166 | if (snaptrace_len) { | ||
3167 | down_write(&mdsc->snap_rwsem); | ||
3168 | ceph_update_snap_trace(mdsc, snaptrace, | ||
3169 | snaptrace + snaptrace_len, | ||
3170 | false, &realm); | ||
3171 | downgrade_write(&mdsc->snap_rwsem); | ||
3172 | } else { | ||
3173 | down_read(&mdsc->snap_rwsem); | ||
3174 | } | ||
3156 | handle_cap_import(mdsc, inode, h, peer, session, | 3175 | handle_cap_import(mdsc, inode, h, peer, session, |
3157 | &cap, &issued); | 3176 | &cap, &issued); |
3158 | handle_cap_grant(mdsc, inode, h, snaptrace, snaptrace_len, | 3177 | handle_cap_grant(mdsc, inode, h, |
3159 | inline_version, inline_data, inline_len, | 3178 | inline_version, inline_data, inline_len, |
3160 | msg->middle, session, cap, issued); | 3179 | msg->middle, session, cap, issued); |
3180 | if (realm) | ||
3181 | ceph_put_snap_realm(mdsc, realm); | ||
3161 | goto done_unlocked; | 3182 | goto done_unlocked; |
3162 | } | 3183 | } |
3163 | 3184 | ||
@@ -3177,7 +3198,7 @@ void ceph_handle_caps(struct ceph_mds_session *session, | |||
3177 | case CEPH_CAP_OP_GRANT: | 3198 | case CEPH_CAP_OP_GRANT: |
3178 | __ceph_caps_issued(ci, &issued); | 3199 | __ceph_caps_issued(ci, &issued); |
3179 | issued |= __ceph_caps_dirty(ci); | 3200 | issued |= __ceph_caps_dirty(ci); |
3180 | handle_cap_grant(mdsc, inode, h, NULL, 0, | 3201 | handle_cap_grant(mdsc, inode, h, |
3181 | inline_version, inline_data, inline_len, | 3202 | inline_version, inline_data, inline_len, |
3182 | msg->middle, session, cap, issued); | 3203 | msg->middle, session, cap, issued); |
3183 | goto done_unlocked; | 3204 | goto done_unlocked; |