Commit 3d7ded4d authored by Sage Weil's avatar Sage Weil

ceph: release cap on import if we don't have the inode

If we get an IMPORT that give us a cap, but we don't have the inode, queue
a release (and try to send it immediately) so that the MDS doesn't get
stuck waiting for us.
Signed-off-by: default avatarSage Weil <sage@newdream.net>
parent 9dbd412f
...@@ -981,19 +981,10 @@ static int send_cap_msg(struct ceph_mds_session *session, ...@@ -981,19 +981,10 @@ static int send_cap_msg(struct ceph_mds_session *session,
return 0; return 0;
} }
/* static void __queue_cap_release(struct ceph_mds_session *session,
* Queue cap releases when an inode is dropped from our cache. Since u64 ino, u64 cap_id, u32 migrate_seq,
* inode is about to be destroyed, there is no need for i_lock. u32 issue_seq)
*/
void ceph_queue_caps_release(struct inode *inode)
{ {
struct ceph_inode_info *ci = ceph_inode(inode);
struct rb_node *p;
p = rb_first(&ci->i_caps);
while (p) {
struct ceph_cap *cap = rb_entry(p, struct ceph_cap, ci_node);
struct ceph_mds_session *session = cap->session;
struct ceph_msg *msg; struct ceph_msg *msg;
struct ceph_mds_cap_release *head; struct ceph_mds_cap_release *head;
struct ceph_mds_cap_item *item; struct ceph_mds_cap_item *item;
...@@ -1003,25 +994,24 @@ void ceph_queue_caps_release(struct inode *inode) ...@@ -1003,25 +994,24 @@ void ceph_queue_caps_release(struct inode *inode)
msg = list_first_entry(&session->s_cap_releases, msg = list_first_entry(&session->s_cap_releases,
struct ceph_msg, list_head); struct ceph_msg, list_head);
dout(" adding %p release to mds%d msg %p (%d left)\n", dout(" adding %llx release to mds%d msg %p (%d left)\n",
inode, session->s_mds, msg, session->s_num_cap_releases); ino, session->s_mds, msg, session->s_num_cap_releases);
BUG_ON(msg->front.iov_len + sizeof(*item) > PAGE_CACHE_SIZE); BUG_ON(msg->front.iov_len + sizeof(*item) > PAGE_CACHE_SIZE);
head = msg->front.iov_base; head = msg->front.iov_base;
head->num = cpu_to_le32(le32_to_cpu(head->num) + 1); head->num = cpu_to_le32(le32_to_cpu(head->num) + 1);
item = msg->front.iov_base + msg->front.iov_len; item = msg->front.iov_base + msg->front.iov_len;
item->ino = cpu_to_le64(ceph_ino(inode)); item->ino = cpu_to_le64(ino);
item->cap_id = cpu_to_le64(cap->cap_id); item->cap_id = cpu_to_le64(cap_id);
item->migrate_seq = cpu_to_le32(cap->mseq); item->migrate_seq = cpu_to_le32(migrate_seq);
item->seq = cpu_to_le32(cap->issue_seq); item->seq = cpu_to_le32(issue_seq);
session->s_num_cap_releases--; session->s_num_cap_releases--;
msg->front.iov_len += sizeof(*item); msg->front.iov_len += sizeof(*item);
if (le32_to_cpu(head->num) == CEPH_CAPS_PER_RELEASE) { if (le32_to_cpu(head->num) == CEPH_CAPS_PER_RELEASE) {
dout(" release msg %p full\n", msg); dout(" release msg %p full\n", msg);
list_move_tail(&msg->list_head, list_move_tail(&msg->list_head, &session->s_cap_releases_done);
&session->s_cap_releases_done);
} else { } else {
dout(" release msg %p at %d/%d (%d)\n", msg, dout(" release msg %p at %d/%d (%d)\n", msg,
(int)le32_to_cpu(head->num), (int)le32_to_cpu(head->num),
...@@ -1029,6 +1019,24 @@ void ceph_queue_caps_release(struct inode *inode) ...@@ -1029,6 +1019,24 @@ void ceph_queue_caps_release(struct inode *inode)
(int)msg->front.iov_len); (int)msg->front.iov_len);
} }
spin_unlock(&session->s_cap_lock); spin_unlock(&session->s_cap_lock);
}
/*
* Queue cap releases when an inode is dropped from our cache. Since
* inode is about to be destroyed, there is no need for i_lock.
*/
void ceph_queue_caps_release(struct inode *inode)
{
struct ceph_inode_info *ci = ceph_inode(inode);
struct rb_node *p;
p = rb_first(&ci->i_caps);
while (p) {
struct ceph_cap *cap = rb_entry(p, struct ceph_cap, ci_node);
struct ceph_mds_session *session = cap->session;
__queue_cap_release(session, ceph_ino(inode), cap->cap_id,
cap->mseq, cap->issue_seq);
p = rb_next(p); p = rb_next(p);
__ceph_remove_cap(cap); __ceph_remove_cap(cap);
} }
...@@ -2655,7 +2663,7 @@ void ceph_handle_caps(struct ceph_mds_session *session, ...@@ -2655,7 +2663,7 @@ void ceph_handle_caps(struct ceph_mds_session *session,
struct ceph_mds_caps *h; struct ceph_mds_caps *h;
int mds = session->s_mds; int mds = session->s_mds;
int op; int op;
u32 seq; u32 seq, mseq;
struct ceph_vino vino; struct ceph_vino vino;
u64 cap_id; u64 cap_id;
u64 size, max_size; u64 size, max_size;
...@@ -2675,6 +2683,7 @@ void ceph_handle_caps(struct ceph_mds_session *session, ...@@ -2675,6 +2683,7 @@ void ceph_handle_caps(struct ceph_mds_session *session,
vino.snap = CEPH_NOSNAP; vino.snap = CEPH_NOSNAP;
cap_id = le64_to_cpu(h->cap_id); cap_id = le64_to_cpu(h->cap_id);
seq = le32_to_cpu(h->seq); seq = le32_to_cpu(h->seq);
mseq = le32_to_cpu(h->migrate_seq);
size = le64_to_cpu(h->size); size = le64_to_cpu(h->size);
max_size = le64_to_cpu(h->max_size); max_size = le64_to_cpu(h->max_size);
...@@ -2689,6 +2698,17 @@ void ceph_handle_caps(struct ceph_mds_session *session, ...@@ -2689,6 +2698,17 @@ void ceph_handle_caps(struct ceph_mds_session *session,
vino.snap, inode); vino.snap, inode);
if (!inode) { if (!inode) {
dout(" i don't have ino %llx\n", vino.ino); dout(" i don't have ino %llx\n", vino.ino);
if (op == CEPH_CAP_OP_IMPORT)
__queue_cap_release(session, vino.ino, cap_id,
mseq, seq);
/*
* send any full release message to try to move things
* along for the mds (who clearly thinks we still have this
* cap).
*/
ceph_send_cap_releases(mdsc, session);
goto done; goto done;
} }
......
...@@ -1176,7 +1176,7 @@ static int check_cap_flush(struct ceph_mds_client *mdsc, u64 want_flush_seq) ...@@ -1176,7 +1176,7 @@ static int check_cap_flush(struct ceph_mds_client *mdsc, u64 want_flush_seq)
/* /*
* called under s_mutex * called under s_mutex
*/ */
static void send_cap_releases(struct ceph_mds_client *mdsc, void ceph_send_cap_releases(struct ceph_mds_client *mdsc,
struct ceph_mds_session *session) struct ceph_mds_session *session)
{ {
struct ceph_msg *msg; struct ceph_msg *msg;
...@@ -2693,7 +2693,7 @@ static void delayed_work(struct work_struct *work) ...@@ -2693,7 +2693,7 @@ static void delayed_work(struct work_struct *work)
add_cap_releases(mdsc, s, -1); add_cap_releases(mdsc, s, -1);
if (s->s_state == CEPH_MDS_SESSION_OPEN || if (s->s_state == CEPH_MDS_SESSION_OPEN ||
s->s_state == CEPH_MDS_SESSION_HUNG) s->s_state == CEPH_MDS_SESSION_HUNG)
send_cap_releases(mdsc, s); ceph_send_cap_releases(mdsc, s);
mutex_unlock(&s->s_mutex); mutex_unlock(&s->s_mutex);
ceph_put_mds_session(s); ceph_put_mds_session(s);
......
...@@ -322,6 +322,9 @@ static inline void ceph_mdsc_put_request(struct ceph_mds_request *req) ...@@ -322,6 +322,9 @@ static inline void ceph_mdsc_put_request(struct ceph_mds_request *req)
kref_put(&req->r_kref, ceph_mdsc_release_request); kref_put(&req->r_kref, ceph_mdsc_release_request);
} }
extern void ceph_send_cap_releases(struct ceph_mds_client *mdsc,
struct ceph_mds_session *session);
extern void ceph_mdsc_pre_umount(struct ceph_mds_client *mdsc); extern void ceph_mdsc_pre_umount(struct ceph_mds_client *mdsc);
extern char *ceph_mdsc_build_path(struct dentry *dentry, int *plen, u64 *base, extern char *ceph_mdsc_build_path(struct dentry *dentry, int *plen, u64 *base,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment