return have;
}
+static void __touch_cap(struct ceph_cap *cap)
+{
+ struct ceph_mds_session *s = cap->session;
+
+ dout(20, "__touch_cap %p cap %p mds%d\n", &cap->ci->vfs_inode, cap,
+ s->s_mds);
+ spin_lock(&s->s_cap_lock);
+ list_move_tail(&cap->session_caps, &s->s_caps);
+ spin_unlock(&s->s_cap_lock);
+}
+
+/*
+ * Return true if we hold the given mask. And move the cap(s) to the front
+ * of their respective LRUs.
+ */
+int __ceph_caps_issued_mask(struct ceph_inode_info *ci, int mask, int touch)
+{
+ struct ceph_cap *cap;
+ struct rb_node *p;
+ int have = ci->i_snap_caps;
+
+ if ((have & mask) == mask) {
+ dout(30, "__ceph_caps_issued_mask %p snap issued %s"
+ " (mask %s)\n", &ci->vfs_inode,
+ ceph_cap_string(have),
+ ceph_cap_string(mask));
+ return 1;
+ }
+
+ 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))
+ continue;
+ if ((cap->issued & mask) == mask) {
+ dout(30, "__ceph_caps_issued_mask %p cap %p issued %s"
+ " (mask %s)\n", &ci->vfs_inode, cap,
+ ceph_cap_string(cap->issued),
+ ceph_cap_string(mask));
+ if (touch)
+ __touch_cap(cap);
+ return 1;
+ }
+
+ /* does a combination of caps satisfy mask? */
+ have |= cap->issued;
+ if ((have & mask) == mask) {
+ dout(30, "__ceph_caps_issued_mask %p combo issued %s"
+ " (mask %s)\n", &ci->vfs_inode,
+ ceph_cap_string(cap->issued),
+ ceph_cap_string(mask));
+ if (touch) {
+ struct rb_node *q;
+
+ __touch_cap(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))
+ continue;
+ __touch_cap(cap);
+ }
+ }
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
/*
* Return mask of caps currently being revoked by an MDS.
*/
if ((filp->f_pos == 2 || fi->dentry) &&
!ceph_test_opt(client, NOASYNCREADDIR) &&
(ci->i_ceph_flags & CEPH_I_COMPLETE) &&
- (__ceph_caps_issued(ci, NULL) & CEPH_CAP_FILE_SHARED)) {
+ __ceph_caps_issued_mask(ci, CEPH_CAP_FILE_SHARED, 1)) {
err = __dcache_readdir(filp, dirent, filldir);
if (err != -EAGAIN) {
spin_unlock(&inode->i_lock);
client->mount_args.snapdir_name,
dentry->d_name.len) &&
(ci->i_ceph_flags & CEPH_I_COMPLETE) &&
- (__ceph_caps_issued(ci, NULL) & CEPH_CAP_FILE_SHARED)) {
+ (__ceph_caps_issued_mask(ci, CEPH_CAP_FILE_SHARED, 1))) {
di->offset = ci->i_max_offset++;
spin_unlock(&dir->i_lock);
dout(10, " dir %p complete, -ENOENT\n", dir);
spin_lock(&dir->i_lock);
if (ci->i_rdcache_gen == di->lease_rdcache_gen)
- valid = __ceph_caps_issued(ci, NULL) & CEPH_CAP_FILE_SHARED;
+ valid = __ceph_caps_issued_mask(ci, CEPH_CAP_FILE_SHARED, 1);
spin_unlock(&dir->i_lock);
dout(20, "dir_lease_is_valid dir %p v%u dentry %p v%u = %d\n",
dir, (unsigned)ci->i_rdcache_gen, dentry,
}
dout(30, "do_getattr inode %p mask %s\n", inode, ceph_cap_string(mask));
- if (ceph_caps_issued_mask(ceph_inode(inode), mask))
+ if (ceph_caps_issued_mask(ceph_inode(inode), mask, 1))
return 0;
req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_GETATTR, USE_ANY_MDS);
int err;
struct _ceph_vir_xattr_cb *vir_xattr;
struct ceph_inode_xattr *xattr;
- int issued;
/* let's see if a virtual xattr was requested */
vir_xattr = _ceph_match_vir_xattr(name);
return (vir_xattr->getxattr_cb)(ci, value, size);
spin_lock(&inode->i_lock);
- issued = __ceph_caps_issued(ci, NULL);
- dout(10, "getxattr %p issued %s ver=%lld index_ver=%lld\n", inode,
- ceph_cap_string(issued),
- ci->i_xattrs.version, ci->i_xattrs.index_version);
+ dout(10, "getxattr %p ver=%lld index_ver=%lld\n", inode,
+ ci->i_xattrs.version, ci->i_xattrs.index_version);
- if ((issued & CEPH_CAP_XATTR_SHARED) &&
+ if (__ceph_caps_issued_mask(ci, CEPH_CAP_XATTR_SHARED, 1) &&
(ci->i_xattrs.index_version >= ci->i_xattrs.version)) {
goto get_xattr;
} else {
int err;
u32 len;
int i;
- int issued;
spin_lock(&inode->i_lock);
- issued = __ceph_caps_issued(ci, NULL);
- dout(10, "listxattr %p issued %s ver=%lld index_ver=%lld\n", inode,
- ceph_cap_string(issued),
- ci->i_xattrs.version, ci->i_xattrs.index_version);
+ dout(10, "listxattr %p ver=%lld index_ver=%lld\n", inode,
+ ci->i_xattrs.version, ci->i_xattrs.index_version);
- if ((issued & CEPH_CAP_XATTR_SHARED) &&
+ if (__ceph_caps_issued_mask(ci, CEPH_CAP_XATTR_SHARED, 1) &&
(ci->i_xattrs.index_version > ci->i_xattrs.version)) {
goto list_xattr;
} else {
spin_unlock(&inode->i_lock);
err = ceph_send_removexattr(dentry, name);
return err;
-
}
}
extern int __ceph_caps_issued(struct ceph_inode_info *ci, int *implemented);
+extern int __ceph_caps_issued_mask(struct ceph_inode_info *ci, int mask, int t);
static inline int ceph_caps_issued(struct ceph_inode_info *ci)
{
return issued;
}
-static inline int ceph_caps_issued_mask(struct ceph_inode_info *ci, int mask)
+static inline int ceph_caps_issued_mask(struct ceph_inode_info *ci, int mask,
+ int touch)
{
- return (ceph_caps_issued(ci) & mask) == mask;
+ int r;
+ spin_lock(&ci->vfs_inode.i_lock);
+ r = __ceph_caps_issued_mask(ci, mask, touch);
+ spin_unlock(&ci->vfs_inode.i_lock);
+ return r;
}
static inline int __ceph_caps_dirty(struct ceph_inode_info *ci)