for (i=0; i<ci->i_nr_caps; i++)
if (ci->i_caps[i].mds == mds) break;
if (i == ci->i_nr_caps) {
+ for (i=0; i<ci->i_nr_caps; i++)
+ if (ci->i_caps[i].mds < 0) break;
if (i == ci->i_max_caps) {
/* realloc */
void *o = ci->i_caps;
kfree(o);
ci->i_max_caps *= 2;
}
+ if (i == ci->i_nr_caps)
+ ci->i_nr_caps++;
+
ci->i_caps[i].ci = ci;
ci->i_caps[i].caps = 0;
ci->i_caps[i].mds = mds;
ci->i_caps[i].seq = 0;
ci->i_caps[i].flags = 0;
- ci->i_nr_caps++;
ci->i_caps[i].session = session;
spin_lock(&session->s_cap_lock);
list_add(&ci->i_caps[i].session_caps, &session->s_caps);
session->s_nr_caps++;
spin_unlock(&session->s_cap_lock);
+
+ if (ci->i_nr_caps == 1) {
+ dout(10, "igrab on %p\n", inode);
+ igrab(inode);
+ }
}
dout(10, "add_cap inode %p (%lu) got cap %d %xh now %xh seq %d from %d\n",
inode, inode->i_ino, i, cap, cap|ci->i_caps[i].caps, seq, mds);
ci->i_caps[i].caps |= cap;
ci->i_caps[i].seq = seq;
- if (ci->i_nr_caps == 1)
- igrab(inode);
return &ci->i_caps[i];
}
spin_lock(&session->s_cap_lock);
list_del(&cap->session_caps);
session->s_nr_caps--;
- spin_unlock(&session->s_cap_lock);
cap->session = 0;
+ spin_unlock(&session->s_cap_lock);
+}
+
+void ceph_remove_cap(struct ceph_inode_info *ci, int mds)
+{
+ int i;
+ int was = ci->i_nr_caps;
+ dout(10, "remove_cap on %p for mds%d\n", &ci->vfs_inode, mds);
+ for (i=0; i<ci->i_nr_caps; i++) {
+ if (ci->i_caps[i].mds != mds)
+ continue;
+ dout(10, "remove_cap removing %p\n", &ci->i_caps[i]);
+ __remove_cap(&ci->i_caps[i]); /* remove from list */
+ if (i == ci->i_nr_caps-1) {
+ do {
+ ci->i_nr_caps--;
+ } while (ci->i_nr_caps &&
+ ci->i_caps[ci->i_nr_caps-1].mds < 0);
+ break;
+ }
+ ci->i_caps[i].mds = -1;
+ ci->i_caps[i].caps = 0;
+ ci->i_caps[i].seq = 0;
+ }
+ if (was > 0 && ci->i_nr_caps == 0) {
+ dout(10, "iput on %p\n", &ci->vfs_inode);
+ iput(&ci->vfs_inode);
+ }
}
void ceph_remove_caps(struct ceph_inode_info *ci)
if (ci->i_nr_caps) {
for (i=0; i<ci->i_nr_caps; i++)
__remove_cap(&ci->i_caps[i]);
- iput(&ci->vfs_inode);
ci->i_nr_caps = 0;
if (ci->i_caps != ci->i_caps_static) {
kfree(ci->i_caps);
ci->i_caps = ci->i_caps_static;
ci->i_max_caps = STATIC_CAPS;
}
+ dout(10, "iput on %p\n", &ci->vfs_inode);
+ iput(&ci->vfs_inode);
}
}
return 0;
}
+static void close_session(struct ceph_mds_client *mdsc, struct ceph_mds_session *session)
+{
+ int mds = session->s_mds;
+ struct ceph_msg *msg;
+
+ dout(10, "close_session to mds%d\n", mds);
+ msg = create_session_msg(CEPH_SESSION_REQUEST_CLOSE, session->s_cap_seq);
+ if (IS_ERR(msg))
+ return;// PTR_ERR(msg); /* fixme */
+ session->s_state = CEPH_MDS_SESSION_CLOSING;
+ send_msg_mds(mdsc, msg, mds);
+}
+
+static void remove_session_caps(struct ceph_mds_session *session)
+{
+ struct ceph_inode_cap *cap;
+ struct ceph_inode_info *ci;
+
+ /*
+ * fixme: when we start locking the inode, make sure
+ * we don't deadlock with __remove_cap in inode.c.
+ */
+ dout(10, "remove_session_caps on %p\n", session);
+ spin_lock(&session->s_cap_lock);
+ while (session->s_nr_caps > 0) {
+ cap = list_entry(session->s_caps.next, struct ceph_inode_cap, session_caps);
+ ci = cap->ci;
+ igrab(&ci->vfs_inode);
+ dout(10, "removing cap %p, ci is %p, inode is %p\n", cap, ci, &ci->vfs_inode);
+ spin_unlock(&session->s_cap_lock);
+ ceph_remove_cap(ci, session->s_mds);
+ spin_lock(&session->s_cap_lock);
+ }
+ BUG_ON(session->s_nr_caps > 0);
+ spin_unlock(&session->s_cap_lock);
+}
+
void ceph_mdsc_handle_session(struct ceph_mds_client *mdsc, struct ceph_msg *msg)
{
__u32 op;
dout(1, "ignoring session close from mds%d, seq %llu < my seq %llu\n",
msg->hdr.src.name.num, seq, session->s_cap_seq);
}
+ remove_session_caps(session);
ceph_mdsc_put_session(session);
+ complete(&mdsc->session_close_waiters);
break;
case CEPH_SESSION_RENEWCAPS:
/* exported functions */
-void schedule_delayed(struct ceph_mds_client *mdsc)
-{
- schedule_delayed_work(&mdsc->delayed_work, HZ*60);
-}
-
-void delayed_work(struct work_struct *work);
-
-void ceph_mdsc_init(struct ceph_mds_client *mdsc, struct ceph_client *client)
-{
- spin_lock_init(&mdsc->lock);
- mdsc->client = client;
- mdsc->mdsmap = 0; /* none yet */
- mdsc->sessions = 0;
- mdsc->max_sessions = 0;
- mdsc->last_tid = 0;
- INIT_RADIX_TREE(&mdsc->request_tree, GFP_KERNEL);
- mdsc->last_requested_map = 0;
- init_completion(&mdsc->map_waiters);
- INIT_DELAYED_WORK(&mdsc->delayed_work, delayed_work);
-
- /* hack fixme */
- schedule_delayed(mdsc);
-}
-
-void ceph_mdsc_stop(struct ceph_mds_client *mdsc)
-{
- /* close sessions, caps */
- /* IMPLEMENT ME */
- cancel_delayed_work_sync(&mdsc->delayed_work);
-}
-
-
struct ceph_msg *
ceph_mdsc_create_request(struct ceph_mds_client *mdsc, int op,
ceph_ino_t ino1, const char *path1,
return 0;
}
+
+/*
+ * delayed work -- renew caps with mds
+ */
+void schedule_delayed(struct ceph_mds_client *mdsc)
+{
+ schedule_delayed_work(&mdsc->delayed_work, HZ*60);
+}
+
void delayed_work(struct work_struct *work)
{
int i;
schedule_delayed(mdsc);
}
+
+void ceph_mdsc_init(struct ceph_mds_client *mdsc, struct ceph_client *client)
+{
+ spin_lock_init(&mdsc->lock);
+ mdsc->client = client;
+ mdsc->mdsmap = 0; /* none yet */
+ mdsc->sessions = 0;
+ mdsc->max_sessions = 0;
+ mdsc->last_tid = 0;
+ INIT_RADIX_TREE(&mdsc->request_tree, GFP_KERNEL);
+ mdsc->last_requested_map = 0;
+ init_completion(&mdsc->map_waiters);
+ init_completion(&mdsc->session_close_waiters);
+ INIT_DELAYED_WORK(&mdsc->delayed_work, delayed_work);
+
+ /* hack fixme */
+ schedule_delayed(mdsc);
+}
+
+void ceph_mdsc_stop(struct ceph_mds_client *mdsc)
+{
+ int i;
+ int n;
+
+ dout(10, "stop\n");
+
+ /* close sessions, caps */
+ for (;;) {
+ dout(10, "closing sessions\n");
+ n = 0;
+ for (i=0; i<mdsc->max_sessions; i++) {
+ if (mdsc->sessions[i] == 0 ||
+ mdsc->sessions[i]->s_state >= CEPH_MDS_SESSION_CLOSING)
+ continue;
+ close_session(mdsc, mdsc->sessions[i]);
+ n++;
+ }
+ if (n == 0) break;
+ dout(10, "waiting for sessions to close\n");
+ wait_for_completion(&mdsc->session_close_waiters);
+ }
+
+ cancel_delayed_work_sync(&mdsc->delayed_work); /* cancel timer */
+}
+
+
+
/* eof */