}
/*
- * Remove or place the given cap on the session clean_caps list
- * (non-dirty or non-auth caps). A cap belongs on the clean caps list
- * IFF it is non-auth or the inode has no dirty caps.
+ * Touch cap timestamp and, if clean, move to end of lru.
+ */
+void __touch_cap(struct ceph_cap *cap)
+{
+ cap->last_used = jiffies;
+ if (!list_empty(&cap->session_clean_caps)) {
+ spin_lock(&cap->session->s_clean_caps_lock);
+ list_del_init(&cap->session_clean_caps);
+ list_add(&cap->session_clean_caps, &cap->session->s_clean_caps);
+ spin_unlock(&cap->session->s_clean_caps_lock);
+ }
+}
+
+/*
+ * Remove or place the given cap on the session clean_caps list A cap
+ * belongs on the clean caps list IFF wanted == 0 AND dirty == 0.
+ *
+ * Also touch the cap last_used (i.e., either call __touch_cap or
+ * __adjust_cap_listing, but not both).
*
- * Caller must hold s_mutex.
+ * Ignore auth/non-auth status for now.
*/
-static void __adjust_cap_listing(struct ceph_mds_session *session,
- struct ceph_inode_info *ci,
- struct ceph_cap *cap)
+static void __adjust_cap_listing(struct ceph_inode_info *ci,
+ struct ceph_cap *cap,
+ int wanted)
{
+ struct ceph_mds_session *session = cap->session;
int dirty = cap->flushing | ci->i_dirty_caps;
- if (dirty && ci->i_auth_cap == cap) {
- /* remove from clean_caps */
- if (!list_empty(&cap->session_clean_caps)) {
- dout(20, "adjust_cap_listing %p %p dirty (%s)\n",
- &ci->vfs_inode, cap, ceph_cap_string(dirty));
- list_del_init(&cap->session_clean_caps);
- }
- } else {
+ spin_lock(&session->s_clean_caps_lock);
+ if (wanted == 0 && dirty == 0) {
/* move to tail of clean_caps lru */
if (!list_empty(&cap->session_clean_caps))
list_del_init(&cap->session_clean_caps);
dout(20, "adjust_cap_listing %p %p clean\n",
&ci->vfs_inode, cap);
list_add_tail(&cap->session_clean_caps, &session->s_clean_caps);
+ cap->last_used = jiffies;
+ } else {
+ /* remove from clean_caps */
+ if (!list_empty(&cap->session_clean_caps)) {
+ dout(20, "adjust_cap_listing %p %p dirty (%s)\n",
+ &ci->vfs_inode, cap, ceph_cap_string(dirty));
+ list_del_init(&cap->session_clean_caps);
+ }
}
+ spin_unlock(&session->s_clean_caps_lock);
}
/*
struct ceph_cap *cap;
int mds = session->s_mds;
int is_first = 0;
+ int all_wanted;
dout(10, "add_cap %p mds%d cap %llx %s seq %d\n", inode,
session->s_mds, cap_id, ceph_cap_string(issued), seq);
ci->i_auth_cap = NULL;
/* Put cap on proper session list */
- __adjust_cap_listing(session, ci, cap);
+ all_wanted = wanted | __ceph_caps_wanted(ci);
+ __adjust_cap_listing(ci, cap, all_wanted);
dout(10, "add_cap inode %p (%llx.%llx) cap %p %s now %s seq %d mds%d\n",
inode, ceph_vinop(inode), cap, ceph_cap_string(issued),
return 1;
}
-/*
- * Touch cap timestamp and, if clean, move to end of lru.
- */
-void __touch_cap(struct ceph_cap *cap)
-{
- cap->last_used = jiffies;
- if (!list_empty(&cap->session_clean_caps)) {
- spin_lock(&cap->session->s_clean_caps_lock);
- list_del_init(&cap->session_clean_caps);
- list_add(&cap->session_clean_caps, &cap->session->s_clean_caps);
- spin_unlock(&cap->session->s_clean_caps_lock);
- }
-}
-
/*
* Return set of valid cap bits issued to us. Note that caps time
* out, and may be invalidated in bulk if the client session times out
wake = 1;
}
- __adjust_cap_listing(session, ci, cap);
+ __adjust_cap_listing(ci, cap, wanted);
spin_unlock(&inode->i_lock);
if (writeback) {
__cap_delay_cancel(&ceph_inode_to_client(inode)->mdsc,
ci);
} else {
- __adjust_cap_listing(session, ci, cap);
+ __adjust_cap_listing(ci, cap, __ceph_caps_wanted(ci));
}
spin_unlock(&inode->i_lock);
if (removed_last)
dout(20, "put_fmode %p fmode %d %d -> %d\n", inode, fmode,
ci->i_nr_by_mode[fmode], ci->i_nr_by_mode[fmode]-1);
BUG_ON(ci->i_nr_by_mode[fmode] == 0);
- if (--ci->i_nr_by_mode[fmode] == 0)
+ if (--ci->i_nr_by_mode[fmode] == 0) {
last++;
+
+ /* maybe turn caps into rdcaps? */
+ if (__ceph_caps_wanted(ci) == 0) {
+ struct rb_node *p;
+ struct ceph_cap *cap;
+
+ for (p = rb_first(&ci->i_caps); p; p = rb_next(p)) {
+ cap = rb_entry(p, struct ceph_cap, ci_node);
+ __adjust_cap_listing(ci, cap, 0);
+ }
+ }
+ }
spin_unlock(&inode->i_lock);
if (last && ci->i_vino.snap == CEPH_NOSNAP)