<< " seq " << dn->lease_seq
<< dendl;
- if (!dn->inode || dn->inode->caps_issued_mask(mask)) {
+ if (!dn->inode || dn->inode->caps_issued_mask(mask, true)) {
// is dn lease valid?
utime_t now = ceph_clock_now();
if (dn->lease_mds >= 0 &&
<< " vs lease_gen " << dn->lease_gen << dendl;
}
// dir lease?
- if (dir->caps_issued_mask(CEPH_CAP_FILE_SHARED)) {
+ if (dir->caps_issued_mask(CEPH_CAP_FILE_SHARED, true)) {
if (dn->cap_shared_gen == dir->shared_gen &&
- (!dn->inode || dn->inode->caps_issued_mask(mask)))
+ (!dn->inode || dn->inode->caps_issued_mask(mask, true)))
goto hit_dn;
if (!dn->inode && (dir->flags & I_COMPLETE)) {
ldout(cct, 10) << __func__ << " concluded ENOENT locally for "
}
} else {
// can we conclude ENOENT locally?
- if (dir->caps_issued_mask(CEPH_CAP_FILE_SHARED) &&
+ if (dir->caps_issued_mask(CEPH_CAP_FILE_SHARED, true) &&
(dir->flags & I_COMPLETE)) {
ldout(cct, 10) << __func__ << " concluded ENOENT locally for " << *dir << " dn '" << dname << "'" << dendl;
return -ENOENT;
int Client::_getattr(Inode *in, int mask, const UserPerm& perms, bool force)
{
- bool yes = in->caps_issued_mask(mask);
+ bool yes = in->caps_issued_mask(mask, true);
ldout(cct, 10) << __func__ << " mask " << ccap_string(mask) << " issued=" << yes << dendl;
if (yes && !force)
<< dendl;
if (dirp->inode->snapid != CEPH_SNAPDIR &&
dirp->inode->is_complete_and_ordered() &&
- dirp->inode->caps_issued_mask(CEPH_CAP_FILE_SHARED)) {
+ dirp->inode->caps_issued_mask(CEPH_CAP_FILE_SHARED, true)) {
int err = _readdir_cache_cb(dirp, cb, p, caps, getref);
if (err != -EAGAIN)
return err;
unsigned mask = statx_to_mask(flags, want);
int r = 0;
- if (mask && !f->inode->caps_issued_mask(mask)) {
+ if (mask && !f->inode->caps_issued_mask(mask, true)) {
r = _getattr(f->inode, mask, perms);
if (r < 0) {
ldout(cct, 3) << "fstatx exit on error!" << dendl;
int res = 0;
unsigned mask = statx_to_mask(flags, want);
- if (mask && !in->caps_issued_mask(mask))
+ if (mask && !in->caps_issued_mask(mask, true))
res = _ll_getattr(in, mask, perms);
if (res == 0)
}
}
-bool Inode::caps_issued_mask(unsigned mask)
+/**
+ * caps_issued_mask - check whether we have all of the caps in the mask
+ * @mask: mask to check against
+ * @allow_impl: whether the caller can also use caps that are implemented but not issued
+ *
+ * This is the bog standard "check whether we have the required caps" operation.
+ * Typically, we only check against the capset that is currently "issued".
+ * In other words, we ignore caps that have been revoked but not yet released.
+ *
+ * Some callers (particularly those doing attribute retrieval) can also make
+ * use of the full set of "implemented" caps to satisfy requests from the
+ * cache.
+ *
+ * Those callers should refrain from taking new references to implemented
+ * caps!
+ */
+bool Inode::caps_issued_mask(unsigned mask, bool allow_impl)
{
int c = snap_caps;
+ int i = 0;
+
if ((c & mask) == mask)
return true;
// prefer auth cap
return true;
}
c |= cap.issued;
+ i |= cap.implemented;
}
}
+
+ if (allow_impl)
+ c |= i;
+
if ((c & mask) == mask) {
// bah.. touch them all
for (auto &pair : caps) {