diff options
Diffstat (limited to 'fs/ceph/caps.c')
| -rw-r--r-- | fs/ceph/caps.c | 218 |
1 files changed, 154 insertions, 64 deletions
diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index d51454e995a8..bcb04c6cb92c 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c @@ -549,7 +549,7 @@ static void __cap_delay_requeue_front(struct ceph_mds_client *mdsc, doutc(mdsc->fsc->client, "%p %llx.%llx\n", inode, ceph_vinop(inode)); spin_lock(&mdsc->cap_delay_lock); - ci->i_ceph_flags |= CEPH_I_FLUSH; + set_bit(CEPH_I_FLUSH_BIT, &ci->i_ceph_flags); if (!list_empty(&ci->i_cap_delay_list)) list_del_init(&ci->i_cap_delay_list); list_add(&ci->i_cap_delay_list, &mdsc->cap_delay_list); @@ -785,9 +785,9 @@ void ceph_add_cap(struct inode *inode, * generation of the MDS session (i.e. has not gone 'stale' due to * us losing touch with the mds). */ -static int __cap_is_valid(struct ceph_cap *cap) +static int __cap_is_valid(struct ceph_inode_info *ci, struct ceph_cap *cap) { - struct inode *inode = &cap->ci->netfs.inode; + struct inode *inode = &ci->netfs.inode; struct ceph_client *cl = cap->session->s_mdsc->fsc->client; unsigned long ttl; u32 gen; @@ -822,7 +822,7 @@ int __ceph_caps_issued(struct ceph_inode_info *ci, int *implemented) *implemented = 0; for (p = rb_first(&ci->i_caps); p; p = rb_next(p)) { cap = rb_entry(p, struct ceph_cap, ci_node); - if (!__cap_is_valid(cap)) + if (!__cap_is_valid(ci, cap)) continue; doutc(cl, "%p %llx.%llx cap %p issued %s\n", inode, ceph_vinop(inode), cap, ceph_cap_string(cap->issued)); @@ -855,7 +855,7 @@ int __ceph_caps_issued_other(struct ceph_inode_info *ci, struct ceph_cap *ocap) cap = rb_entry(p, struct ceph_cap, ci_node); if (cap == ocap) continue; - if (!__cap_is_valid(cap)) + if (!__cap_is_valid(ci, cap)) continue; have |= cap->issued; } @@ -866,11 +866,19 @@ int __ceph_caps_issued_other(struct ceph_inode_info *ci, struct ceph_cap *ocap) * Move a cap to the end of the LRU (oldest caps at list head, newest * at list tail). */ -static void __touch_cap(struct ceph_cap *cap) +static void __touch_cap(struct ceph_inode_info *ci, struct ceph_cap *cap) { - struct inode *inode = &cap->ci->netfs.inode; + struct inode *inode = &ci->netfs.inode; struct ceph_mds_session *s = cap->session; struct ceph_client *cl = s->s_mdsc->fsc->client; + static u8 skip_counter; + + if (data_race(++skip_counter)) + /* skip this call most of the time to reduce lock + * contention; the LRU list is still accurate enough + * for ceph_trim_caps() + */ + return; spin_lock(&s->s_cap_lock); if (!s->s_cap_iterator) { @@ -906,7 +914,7 @@ int __ceph_caps_issued_mask(struct ceph_inode_info *ci, int mask, int touch) for (p = rb_first(&ci->i_caps); p; p = rb_next(p)) { cap = rb_entry(p, struct ceph_cap, ci_node); - if (!__cap_is_valid(cap)) + if (!__cap_is_valid(ci, cap)) continue; if ((cap->issued & mask) == mask) { doutc(cl, "mask %p %llx.%llx cap %p issued %s (mask %s)\n", @@ -914,7 +922,7 @@ int __ceph_caps_issued_mask(struct ceph_inode_info *ci, int mask, int touch) ceph_cap_string(cap->issued), ceph_cap_string(mask)); if (touch) - __touch_cap(cap); + __touch_cap(ci, cap); return 1; } @@ -929,15 +937,15 @@ int __ceph_caps_issued_mask(struct ceph_inode_info *ci, int mask, int touch) struct rb_node *q; /* touch this + preceding caps */ - __touch_cap(cap); + __touch_cap(ci, cap); for (q = rb_first(&ci->i_caps); q != p; q = rb_next(q)) { cap = rb_entry(q, struct ceph_cap, ci_node); - if (!__cap_is_valid(cap)) + if (!__cap_is_valid(ci, cap)) continue; if (cap->issued & mask) - __touch_cap(cap); + __touch_cap(ci, cap); } } return 1; @@ -979,6 +987,27 @@ int __ceph_caps_revoking_other(struct ceph_inode_info *ci, return 0; } +/* + * Return true if any cap of this inode holds caps which the MDS has + * revoked, but which we have not released yet. + */ +static bool __ceph_is_any_revoking(const struct ceph_inode_info *ci) +{ + const struct rb_node *p; + + lockdep_assert_held(&ci->i_ceph_lock); + + for (p = rb_first(&ci->i_caps); p; p = rb_next(p)) { + const struct ceph_cap *cap = + rb_entry(p, struct ceph_cap, ci_node); + + if (cap->implemented & ~cap->issued) + return true; + } + + return false; +} + int __ceph_caps_used(struct ceph_inode_info *ci) { int used = 0; @@ -1091,7 +1120,7 @@ int __ceph_caps_mds_wanted(struct ceph_inode_info *ci, bool check) for (p = rb_first(&ci->i_caps); p; p = rb_next(p)) { cap = rb_entry(p, struct ceph_cap, ci_node); - if (check && !__cap_is_valid(cap)) + if (check && !__cap_is_valid(ci, cap)) continue; if (cap == ci->i_auth_cap) mds_wanted |= cap->mds_wanted; @@ -1119,20 +1148,20 @@ int ceph_is_any_caps(struct inode *inode) * caller should hold i_ceph_lock. * caller will not hold session s_mutex if called from destroy_inode. */ -void __ceph_remove_cap(struct ceph_cap *cap, bool queue_release) +static void __ceph_remove_cap(struct ceph_inode_info *ci, struct ceph_cap *cap, bool queue_release) { - struct ceph_mds_session *session = cap->session; - struct ceph_client *cl = session->s_mdsc->fsc->client; - struct ceph_inode_info *ci = cap->ci; - struct inode *inode = &ci->netfs.inode; + struct ceph_mds_session *session; + struct ceph_client *cl; + struct inode *inode; struct ceph_mds_client *mdsc; int removed = 0; - /* 'ci' being NULL means the remove have already occurred */ - if (!ci) { - doutc(cl, "inode is NULL\n"); + if (ceph_cap_is_removed(cap)) return; - } + + session = cap->session; + cl = session->s_mdsc->fsc->client; + inode = &ci->netfs.inode; lockdep_assert_held(&ci->i_ceph_lock); @@ -1158,8 +1187,11 @@ void __ceph_remove_cap(struct ceph_cap *cap, bool queue_release) cap->session = NULL; removed = 1; } - /* protect backpointer with s_cap_lock: see iterate_session_caps */ - cap->ci = NULL; + + /* protect removal marker with both i_ceph_lock and + s_cap_lock, so either one can be used to check for + removal */ + RB_CLEAR_NODE(&cap->ci_node); /* * s_cap_reconnect is protected by s_cap_lock. no one changes @@ -1196,13 +1228,12 @@ void __ceph_remove_cap(struct ceph_cap *cap, bool queue_release) } void ceph_remove_cap(struct ceph_mds_client *mdsc, struct ceph_cap *cap, + struct ceph_inode_info *ci, bool queue_release) { - struct ceph_inode_info *ci = cap->ci; struct ceph_fs_client *fsc; - /* 'ci' being NULL means the remove have already occurred */ - if (!ci) { + if (ceph_cap_is_removed(cap)) { doutc(mdsc->fsc->client, "inode is NULL\n"); return; } @@ -1215,7 +1246,7 @@ void ceph_remove_cap(struct ceph_mds_client *mdsc, struct ceph_cap *cap, !fsc->blocklisted && !ceph_inode_is_shutdown(&ci->netfs.inode)); - __ceph_remove_cap(cap, queue_release); + __ceph_remove_cap(ci, cap, queue_release); } struct cap_msg_args { @@ -1375,7 +1406,7 @@ void __ceph_remove_caps(struct ceph_inode_info *ci) while (p) { struct ceph_cap *cap = rb_entry(p, struct ceph_cap, ci_node); p = rb_next(p); - ceph_remove_cap(mdsc, cap, true); + ceph_remove_cap(mdsc, cap, ci, true); } spin_unlock(&ci->i_ceph_lock); } @@ -1388,11 +1419,11 @@ void __ceph_remove_caps(struct ceph_inode_info *ci) * Make note of max_size reported/requested from mds, revoked caps * that have now been implemented. */ -static void __prep_cap(struct cap_msg_args *arg, struct ceph_cap *cap, +static void __prep_cap(struct cap_msg_args *arg, struct ceph_inode_info *ci, + struct ceph_cap *cap, int op, int flags, int used, int want, int retain, int flushing, u64 flush_tid, u64 oldest_flush_tid) { - struct ceph_inode_info *ci = cap->ci; struct inode *inode = &ci->netfs.inode; struct ceph_client *cl = ceph_inode_to_client(inode); int held, revoking; @@ -1409,7 +1440,7 @@ static void __prep_cap(struct cap_msg_args *arg, struct ceph_cap *cap, ceph_cap_string(revoking)); BUG_ON((retain & CEPH_CAP_PIN) == 0); - ci->i_ceph_flags &= ~CEPH_I_FLUSH; + clear_bit(CEPH_I_FLUSH_BIT, &ci->i_ceph_flags); cap->issued &= retain; /* drop bits we don't want */ /* @@ -1421,6 +1452,9 @@ static void __prep_cap(struct cap_msg_args *arg, struct ceph_cap *cap, cap->implemented &= cap->issued | used; cap->mds_wanted = want; + if ((ci->i_ceph_flags & CEPH_I_FLUSH_FORCE) != 0 && !__ceph_is_any_revoking(ci)) + clear_bit(CEPH_I_FLUSH_FORCE_BIT, &ci->i_ceph_flags); + arg->session = cap->session; arg->ino = ceph_vino(inode).ino; arg->cid = cap->cap_id; @@ -1648,6 +1682,7 @@ static void __ceph_flush_snaps(struct ceph_inode_info *ci, spin_lock(&mdsc->cap_dirty_lock); capsnap->cap_flush.tid = ++mdsc->last_cap_flush_tid; + capsnap->cap_flush.ci = ci; list_add_tail(&capsnap->cap_flush.g_list, &mdsc->cap_flush_list); if (oldest_flush_tid == 0) @@ -1666,7 +1701,7 @@ static void __ceph_flush_snaps(struct ceph_inode_info *ci, last_tid = capsnap->cap_flush.tid; } - ci->i_ceph_flags &= ~CEPH_I_FLUSH_SNAPS; + clear_bit(CEPH_I_FLUSH_SNAPS_BIT, &ci->i_ceph_flags); while (first_tid <= last_tid) { struct ceph_cap *cap = ci->i_auth_cap; @@ -1841,11 +1876,12 @@ struct ceph_cap_flush *ceph_alloc_cap_flush(void) { struct ceph_cap_flush *cf; - cf = kmem_cache_alloc(ceph_cap_flush_cachep, GFP_KERNEL); + cf = kmem_cache_alloc(ceph_cap_flush_cachep, GFP_NOFS); if (!cf) return NULL; cf->is_capsnap = false; + cf->ci = NULL; return cf; } @@ -1931,6 +1967,7 @@ static u64 __mark_caps_flushing(struct inode *inode, doutc(cl, "%p %llx.%llx now !dirty\n", inode, ceph_vinop(inode)); swap(cf, ci->i_prealloc_cap_flush); + cf->ci = ci; cf->caps = flushing; cf->wake = wake; @@ -2026,7 +2063,7 @@ void ceph_check_caps(struct ceph_inode_info *ci, int flags) spin_lock(&ci->i_ceph_lock); if (ci->i_ceph_flags & CEPH_I_ASYNC_CREATE) { - ci->i_ceph_flags |= CEPH_I_ASYNC_CHECK_CAPS; + set_bit(CEPH_I_ASYNC_CHECK_CAPS_BIT, &ci->i_ceph_flags); /* Don't send messages until we get async create reply */ spin_unlock(&ci->i_ceph_lock); @@ -2035,6 +2072,14 @@ void ceph_check_caps(struct ceph_inode_info *ci, int flags) if (ci->i_ceph_flags & CEPH_I_FLUSH) flags |= CHECK_CAPS_FLUSH; + /* + * A revoke whose response was deferred (see handle_cap_grant()) must + * still be acknowledged. Replay the forced flush here so that even a + * check triggered by writeback/invalidation completion sends a cap + * message to the MDS. + */ + if (ci->i_ceph_flags & CEPH_I_FLUSH_FORCE) + flags |= CHECK_CAPS_FLUSH_FORCE; retry: /* Caps wanted by virtue of active open files. */ file_wanted = __ceph_caps_file_wanted(ci); @@ -2207,7 +2252,7 @@ retry: if (want & ~cap->mds_wanted) { if (want & ~(cap->mds_wanted | cap->issued)) goto ack; - if (!__cap_is_valid(cap)) + if (!__cap_is_valid(ci, cap)) goto ack; } @@ -2249,7 +2294,7 @@ ack: mds = cap->mds; /* remember mds, so we don't repeat */ - __prep_cap(&arg, cap, CEPH_CAP_OP_UPDATE, mflags, cap_used, + __prep_cap(&arg, ci, cap, CEPH_CAP_OP_UPDATE, mflags, cap_used, want, retain, flushing, flush_tid, oldest_flush_tid); spin_unlock(&ci->i_ceph_lock); @@ -2311,7 +2356,7 @@ retry_locked: flush_tid = __mark_caps_flushing(inode, session, true, &oldest_flush_tid); - __prep_cap(&arg, cap, CEPH_CAP_OP_FLUSH, CEPH_CLIENT_CAPS_SYNC, + __prep_cap(&arg, ci, cap, CEPH_CAP_OP_FLUSH, CEPH_CLIENT_CAPS_SYNC, __ceph_caps_used(ci), __ceph_caps_wanted(ci), (cap->issued | cap->implemented), flushing, flush_tid, oldest_flush_tid); @@ -2577,7 +2622,7 @@ static void __kick_flushing_caps(struct ceph_mds_client *mdsc, if (ci->i_ceph_flags & CEPH_I_ASYNC_CREATE) return; - ci->i_ceph_flags &= ~CEPH_I_KICK_FLUSH; + clear_bit(CEPH_I_KICK_FLUSH_BIT, &ci->i_ceph_flags); list_for_each_entry_reverse(cf, &ci->i_cap_flush_list, i_list) { if (cf->is_capsnap) { @@ -2586,9 +2631,14 @@ static void __kick_flushing_caps(struct ceph_mds_client *mdsc, } } - list_for_each_entry(cf, &ci->i_cap_flush_list, i_list) { - if (cf->tid < first_tid) + cf = list_first_entry(&ci->i_cap_flush_list, struct ceph_cap_flush, i_list); + while (&cf->i_list != &ci->i_cap_flush_list) { + struct ceph_cap_flush *next; + + if (cf->tid < first_tid) { + cf = list_next_entry(cf, i_list); continue; + } cap = ci->i_auth_cap; if (!(cap && cap->session == session)) { @@ -2598,6 +2648,7 @@ static void __kick_flushing_caps(struct ceph_mds_client *mdsc, } first_tid = cf->tid + 1; + next = list_next_entry(cf, i_list); if (!cf->is_capsnap) { struct cap_msg_args arg; @@ -2605,7 +2656,7 @@ static void __kick_flushing_caps(struct ceph_mds_client *mdsc, doutc(cl, "%p %llx.%llx cap %p tid %llu %s\n", inode, ceph_vinop(inode), cap, cf->tid, ceph_cap_string(cf->caps)); - __prep_cap(&arg, cap, CEPH_CAP_OP_FLUSH, + __prep_cap(&arg, ci, cap, CEPH_CAP_OP_FLUSH, (cf->tid < last_snap_flush ? CEPH_CLIENT_CAPS_PENDING_CAPSNAP : 0), __ceph_caps_used(ci), @@ -2638,6 +2689,7 @@ static void __kick_flushing_caps(struct ceph_mds_client *mdsc, } spin_lock(&ci->i_ceph_lock); + cf = next; } } @@ -2686,7 +2738,7 @@ void ceph_early_kick_flushing_caps(struct ceph_mds_client *mdsc, __kick_flushing_caps(mdsc, session, ci, oldest_flush_tid); } else { - ci->i_ceph_flags |= CEPH_I_KICK_FLUSH; + set_bit(CEPH_I_KICK_FLUSH_BIT, &ci->i_ceph_flags); } spin_unlock(&ci->i_ceph_lock); @@ -2829,7 +2881,7 @@ again: spin_lock(&ci->i_ceph_lock); if ((flags & CHECK_FILELOCK) && - (ci->i_ceph_flags & CEPH_I_ERROR_FILELOCK)) { + test_bit(CEPH_I_ERROR_FILELOCK_BIT, &ci->i_ceph_flags)) { doutc(cl, "%p %llx.%llx error filelock\n", inode, ceph_vinop(inode)); ret = -EIO; @@ -3091,7 +3143,19 @@ int __ceph_get_caps(struct inode *inode, struct ceph_file_info *fi, int need, ret = -ERESTARTSYS; break; } - wait_woken(&wait, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT); + + /* + * If a cap update is lost after + * mds_wanted was raised, waiting + * forever will never make progress. + * Retry the renew path periodically + * so we can resend synchronously. + */ + if (!wait_woken(&wait, TASK_INTERRUPTIBLE, + CEPH_GET_CAPS_WAIT_TIMEOUT)) { + ret = -EUCLEAN; + break; + } } remove_wait_queue(&ci->i_cap_wq, &wait); @@ -3125,7 +3189,8 @@ int __ceph_get_caps(struct inode *inode, struct ceph_file_info *fi, int need, continue; } if (ret == -EUCLEAN) { - /* session was killed, try renew caps */ + /* session was killed or a waited cap + * request needs a retry */ ret = ceph_renew_caps(inode, flags); if (ret == 0) continue; @@ -3207,7 +3272,7 @@ static int ceph_try_drop_cap_snap(struct ceph_inode_info *ci, BUG_ON(capsnap->cap_flush.tid > 0); ceph_put_snap_context(capsnap->context); if (!list_is_last(&capsnap->ci_item, &ci->i_cap_snaps)) - ci->i_ceph_flags |= CEPH_I_FLUSH_SNAPS; + set_bit(CEPH_I_FLUSH_SNAPS_BIT, &ci->i_ceph_flags); list_del(&capsnap->ci_item); ceph_put_cap_snap(capsnap); @@ -3396,7 +3461,7 @@ void ceph_put_wrbuffer_cap_refs(struct ceph_inode_info *ci, int nr, if (ceph_try_drop_cap_snap(ci, capsnap)) { put++; } else { - ci->i_ceph_flags |= CEPH_I_FLUSH_SNAPS; + set_bit(CEPH_I_FLUSH_SNAPS_BIT, &ci->i_ceph_flags); flush_snaps = true; } } @@ -3648,7 +3713,7 @@ static void handle_cap_grant(struct inode *inode, if (ci->i_layout.pool_id != old_pool || extra_info->pool_ns != old_ns) - ci->i_ceph_flags &= ~CEPH_I_POOL_PERM; + clear_bit(CEPH_I_POOL_PERM_BIT, &ci->i_ceph_flags); extra_info->pool_ns = old_ns; @@ -3741,13 +3806,30 @@ static void handle_cap_grant(struct inode *inode, BUG_ON(cap->issued & ~cap->implemented); /* don't let check_caps skip sending a response to MDS for revoke msgs */ - if (!revoke_wait && le32_to_cpu(grant->op) == CEPH_CAP_OP_REVOKE) { - cap->mds_wanted = 0; - flags |= CHECK_CAPS_FLUSH_FORCE; - if (cap == ci->i_auth_cap) - check_caps = 1; /* check auth cap only */ - else - check_caps = 2; /* check all caps */ + if (le32_to_cpu(grant->op) == CEPH_CAP_OP_REVOKE) { + if (revoke_wait) { + /* + * We can't ack the revoke yet: the response is deferred + * until the writeback or cache invalidation queued above + * completes. Set the CEPH_I_FLUSH_FORCE flag to remember + * that a forced cap message is owed so that deferred + * completion (ceph_put_wrbuffer_cap_refs() or the + * invalidate worker, both of which call ceph_check_caps()) + * actually sends one, even if by then the revoked caps look + * unused, the inode is retaining caps, or the MDS has + * re-granted them. Without this, the cap message is never + * sent and the MDS hangs ("isn't responding to + * mclientcaps(revoke)"). + */ + set_bit(CEPH_I_FLUSH_FORCE_BIT, &ci->i_ceph_flags); + } else { + cap->mds_wanted = 0; + flags |= CHECK_CAPS_FLUSH_FORCE; + if (cap == ci->i_auth_cap) + check_caps = 1; /* check auth cap only */ + else + check_caps = 2; /* check all caps */ + } } if (extra_info->inline_version > 0 && @@ -3826,6 +3908,13 @@ static void handle_cap_flush_ack(struct inode *inode, u64 flush_tid, bool wake_ci = false; bool wake_mdsc = false; + /* + * Flush tids are monotonically increasing and acks arrive in + * order under i_ceph_lock, so this is always the latest tid. + * Diagnostic readers use READ_ONCE() without holding the lock. + */ + WRITE_ONCE(ci->i_last_cap_flush_ack, flush_tid); + list_for_each_entry_safe(cf, tmp_cf, &ci->i_cap_flush_list, i_list) { /* Is this the one that was flushed? */ if (cf->tid == flush_tid) @@ -4096,7 +4185,7 @@ retry: goto out_unlock; if (target < 0) { - ceph_remove_cap(mdsc, cap, false); + ceph_remove_cap(mdsc, cap, ci, false); goto out_unlock; } @@ -4133,7 +4222,7 @@ retry: change_auth_cap_ses(ci, tcap->session); } } - ceph_remove_cap(mdsc, cap, false); + ceph_remove_cap(mdsc, cap, ci, false); goto out_unlock; } else if (tsession) { /* add placeholder for the export target */ @@ -4150,7 +4239,7 @@ retry: spin_unlock(&mdsc->cap_dirty_lock); } - ceph_remove_cap(mdsc, cap, false); + ceph_remove_cap(mdsc, cap, ci, false); goto out_unlock; } @@ -4266,7 +4355,7 @@ retry: inode, ceph_vinop(inode), peer, ocap->seq, ocap->mseq, mds, piseq, pmseq); } - ceph_remove_cap(mdsc, ocap, (ph->flags & CEPH_CAP_FLAG_RELEASE)); + ceph_remove_cap(mdsc, ocap, ci, (ph->flags & CEPH_CAP_FLAG_RELEASE)); } *old_issued = issued; @@ -4365,6 +4454,7 @@ void ceph_handle_caps(struct ceph_mds_session *session, snaptrace = h + 1; snaptrace_len = le32_to_cpu(h->snap_trace_len); + ceph_decode_need(&snaptrace, end, snaptrace_len, bad); p = snaptrace + snaptrace_len; if (msg_version >= 2) { @@ -4815,7 +4905,7 @@ int ceph_drop_caps_for_unlink(struct inode *inode) doutc(mdsc->fsc->client, "%p %llx.%llx\n", inode, ceph_vinop(inode)); spin_lock(&mdsc->cap_delay_lock); - ci->i_ceph_flags |= CEPH_I_FLUSH; + set_bit(CEPH_I_FLUSH_BIT, &ci->i_ceph_flags); if (!list_empty(&ci->i_cap_delay_list)) list_del_init(&ci->i_cap_delay_list); list_add_tail(&ci->i_cap_delay_list, @@ -4863,7 +4953,7 @@ int ceph_encode_inode_release(void **p, struct inode *inode, drop &= ~(used | dirty); cap = __get_cap_for_mds(ci, mds); - if (cap && __cap_is_valid(cap)) { + if (cap && __cap_is_valid(ci, cap)) { unless &= cap->issued; if (unless) { if (unless & CEPH_CAP_AUTH_EXCL) @@ -5022,7 +5112,7 @@ int ceph_purge_inode_cap(struct inode *inode, struct ceph_cap *cap, bool *invali cap, ci, inode, ceph_vinop(inode)); is_auth = (cap == ci->i_auth_cap); - __ceph_remove_cap(cap, false); + __ceph_remove_cap(ci, cap, false); if (is_auth) { struct ceph_cap_flush *cf; @@ -5080,7 +5170,7 @@ int ceph_purge_inode_cap(struct inode *inode, struct ceph_cap *cap, bool *invali if (atomic_read(&ci->i_filelock_ref) > 0) { /* make further file lock syscall return -EIO */ - ci->i_ceph_flags |= CEPH_I_ERROR_FILELOCK; + set_bit(CEPH_I_ERROR_FILELOCK_BIT, &ci->i_ceph_flags); pr_warn_ratelimited_client(cl, " dropping file locks for %p %llx.%llx\n", inode, ceph_vinop(inode)); |
