diff options
| author | Sage Weil <sage@newdream.net> | 2011-01-18 11:56:01 -0500 |
|---|---|---|
| committer | Sage Weil <sage@newdream.net> | 2011-01-19 12:23:25 -0500 |
| commit | 088b3f5e9ee2649f5cfc2f08d8ce654e3eeba310 (patch) | |
| tree | ca61373ee6eccd99a2af9a58ef492e099bacce3d | |
| parent | 24be0c481067560b11441e794e27f166a3568863 (diff) | |
ceph: fix flushing of caps vs cap import
If we are mid-flush and a cap is migrated to another node, we need to
resend the cap flush message to the new MDS, and do so with the original
flush_seq to avoid leaking across a sync boundary. Previously we didn't
redo the flush (we only flushed newly dirty data), which would cause a
later sync to hang forever.
Signed-off-by: Sage Weil <sage@newdream.net>
| -rw-r--r-- | fs/ceph/caps.c | 38 |
1 files changed, 34 insertions, 4 deletions
diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index f654c7e933ac..7def3f5903dd 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c | |||
| @@ -1560,9 +1560,10 @@ retry_locked: | |||
| 1560 | /* NOTE: no side-effects allowed, until we take s_mutex */ | 1560 | /* NOTE: no side-effects allowed, until we take s_mutex */ |
| 1561 | 1561 | ||
| 1562 | revoking = cap->implemented & ~cap->issued; | 1562 | revoking = cap->implemented & ~cap->issued; |
| 1563 | if (revoking) | 1563 | dout(" mds%d cap %p issued %s implemented %s revoking %s\n", |
| 1564 | dout(" mds%d revoking %s\n", cap->mds, | 1564 | cap->mds, cap, ceph_cap_string(cap->issued), |
| 1565 | ceph_cap_string(revoking)); | 1565 | ceph_cap_string(cap->implemented), |
| 1566 | ceph_cap_string(revoking)); | ||
| 1566 | 1567 | ||
| 1567 | if (cap == ci->i_auth_cap && | 1568 | if (cap == ci->i_auth_cap && |
| 1568 | (cap->issued & CEPH_CAP_FILE_WR)) { | 1569 | (cap->issued & CEPH_CAP_FILE_WR)) { |
| @@ -1942,6 +1943,35 @@ void ceph_kick_flushing_caps(struct ceph_mds_client *mdsc, | |||
| 1942 | } | 1943 | } |
| 1943 | } | 1944 | } |
| 1944 | 1945 | ||
| 1946 | static void kick_flushing_inode_caps(struct ceph_mds_client *mdsc, | ||
| 1947 | struct ceph_mds_session *session, | ||
| 1948 | struct inode *inode) | ||
| 1949 | { | ||
| 1950 | struct ceph_inode_info *ci = ceph_inode(inode); | ||
| 1951 | struct ceph_cap *cap; | ||
| 1952 | int delayed = 0; | ||
| 1953 | |||
| 1954 | spin_lock(&inode->i_lock); | ||
| 1955 | cap = ci->i_auth_cap; | ||
| 1956 | dout("kick_flushing_inode_caps %p flushing %s flush_seq %lld\n", inode, | ||
| 1957 | ceph_cap_string(ci->i_flushing_caps), ci->i_cap_flush_seq); | ||
| 1958 | __ceph_flush_snaps(ci, &session, 1); | ||
| 1959 | if (ci->i_flushing_caps) { | ||
| 1960 | delayed = __send_cap(mdsc, cap, CEPH_CAP_OP_FLUSH, | ||
| 1961 | __ceph_caps_used(ci), | ||
| 1962 | __ceph_caps_wanted(ci), | ||
| 1963 | cap->issued | cap->implemented, | ||
| 1964 | ci->i_flushing_caps, NULL); | ||
| 1965 | if (delayed) { | ||
| 1966 | spin_lock(&inode->i_lock); | ||
| 1967 | __cap_delay_requeue(mdsc, ci); | ||
| 1968 | spin_unlock(&inode->i_lock); | ||
| 1969 | } | ||
| 1970 | } else { | ||
| 1971 | spin_unlock(&inode->i_lock); | ||
| 1972 | } | ||
| 1973 | } | ||
| 1974 | |||
| 1945 | 1975 | ||
| 1946 | /* | 1976 | /* |
| 1947 | * Take references to capabilities we hold, so that we don't release | 1977 | * Take references to capabilities we hold, so that we don't release |
| @@ -2689,7 +2719,7 @@ static void handle_cap_import(struct ceph_mds_client *mdsc, | |||
| 2689 | ceph_add_cap(inode, session, cap_id, -1, | 2719 | ceph_add_cap(inode, session, cap_id, -1, |
| 2690 | issued, wanted, seq, mseq, realmino, CEPH_CAP_FLAG_AUTH, | 2720 | issued, wanted, seq, mseq, realmino, CEPH_CAP_FLAG_AUTH, |
| 2691 | NULL /* no caps context */); | 2721 | NULL /* no caps context */); |
| 2692 | try_flush_caps(inode, session, NULL); | 2722 | kick_flushing_inode_caps(mdsc, session, inode); |
| 2693 | up_read(&mdsc->snap_rwsem); | 2723 | up_read(&mdsc->snap_rwsem); |
| 2694 | 2724 | ||
| 2695 | /* make sure we re-request max_size, if necessary */ | 2725 | /* make sure we re-request max_size, if necessary */ |
