Inode * Client::add_update_inode(InodeStat *st, utime_t from,
MetaSession *session,
- uid_t request_uid, gid_t request_gid)
+ const UserPerm& request_perms)
{
Inode *in;
bool was_new = false;
if (in->snapid == CEPH_NOSNAP) {
add_update_cap(in, session, st->cap.cap_id, st->cap.caps, st->cap.seq,
st->cap.mseq, inodeno_t(st->cap.realm), st->cap.flags,
- request_uid, request_gid);
+ request_perms);
if (in->auth_cap && in->auth_cap->session == session)
in->max_size = st->max_size;
} else
ldout(cct, 15) << "" << i << ": '" << dname << "'" << dendl;
Inode *in = add_update_inode(&ist, request->sent_stamp, session,
- request->get_uid(), request->get_gid());
+ request->perms);
Dentry *dn;
if (diri->dir->dentries.count(dname)) {
Dentry *olddn = diri->dir->dentries[dname];
}
in = add_update_inode(&ist, request->sent_stamp, session,
- request->get_uid(), request->get_gid());
+ request->perms);
}
Inode *diri = NULL;
if (reply->head.is_dentry) {
diri = add_update_inode(&dirst, request->sent_stamp, session,
- request->get_uid(), request->get_gid());
+ request->perms);
update_dir_dist(diri, &dst); // dir stat info is attached to ..
if (in) {
void Client::add_update_cap(Inode *in, MetaSession *mds_session, uint64_t cap_id,
unsigned issued, unsigned seq, unsigned mseq, inodeno_t realm,
- int flags, uid_t cap_uid, gid_t cap_gid)
+ int flags, const UserPerm& cap_perms)
{
Cap *cap = 0;
mds_rank_t mds = mds_session->mds_num;
cap->seq = seq;
cap->issue_seq = seq;
cap->mseq = mseq;
- cap->latest_uid = cap_uid;
- cap->latest_gid = cap_gid;
+ cap->latest_perms = cap_perms;
ldout(cct, 10) << "add_update_cap issued " << ccap_string(old_caps) << " -> " << ccap_string(cap->issued)
<< " from mds." << mds
<< " on " << *in
const mds_rank_t peer_mds = mds_rank_t(m->peer.mds);
Cap *cap = NULL;
- uid_t cap_uid = -1;
- gid_t cap_gid = -1;
+ UserPerm cap_perms;
if (m->peer.cap_id && in->caps.count(peer_mds)) {
cap = in->caps[peer_mds];
if (cap) {
- cap_uid = cap->latest_uid;
- cap_gid = cap->latest_gid;
+ cap_perms = cap->latest_perms;
}
}
update_snap_trace(m->snapbl);
add_update_cap(in, session, m->get_cap_id(),
m->get_caps(), m->get_seq(), m->get_mseq(), m->get_realm(),
- CEPH_CAP_FLAG_AUTH, cap_uid, cap_gid);
+ CEPH_CAP_FLAG_AUTH, cap_perms);
if (cap && cap->cap_id == m->peer.cap_id) {
remove_cap(cap, (m->peer.flags & CEPH_CAP_FLAG_RELEASE));
add_update_cap(in, tsession, m->peer.cap_id, cap->issued,
m->peer.seq - 1, m->peer.mseq, (uint64_t)-1,
cap == in->auth_cap ? CEPH_CAP_FLAG_AUTH : 0,
- cap->latest_uid, cap->latest_gid);
+ cap->latest_perms);
}
} else {
if (cap == in->auth_cap)
req->head.args.open.mask = 0;
req->set_inode(in);
- UserPerm perms(in->get_best_cap_uid(), in->get_best_cap_gid());
+ // duplicate in case Cap goes away; not sure if that race is a concern?
+ const UserPerm *pperm = in->get_best_perms();
+ UserPerm perms;
+ if (pperm != NULL)
+ perms = *pperm;
int ret = make_request(req, perms);
return ret;
}
void check_cap_issue(Inode *in, Cap *cap, unsigned issued);
void add_update_cap(Inode *in, MetaSession *session, uint64_t cap_id,
unsigned issued, unsigned seq, unsigned mseq, inodeno_t realm,
- int flags, uid_t cap_uid, gid_t cap_gid);
+ int flags, const UserPerm& perms);
void remove_cap(Cap *cap, bool queue_release);
void remove_all_caps(Inode *in);
void remove_session_caps(MetaSession *session);
version_t inline_version, bufferlist& inline_data,
int issued);
Inode *add_update_inode(InodeStat *st, utime_t ttl, MetaSession *session,
- uid_t request_uid, gid_t request_gid);
+ const UserPerm& request_perms);
Dentry *insert_dentry_inode(Dir *dir, const string& dname, LeaseStat *dlease,
Inode *in, utime_t from, MetaSession *session,
Dentry *old_dentry = NULL);
return dirty_caps | flushing_caps;
}
-uid_t Inode::get_best_cap_uid()
+const UserPerm* Inode::get_best_perms()
{
- uid_t any = -1;
+ const UserPerm *perms = NULL;
for (const auto ci : caps) {
- if (ci.second->latest_uid == uid)
- return uid;
- any = ci.second->latest_uid;
- }
- return any;
-}
-
-gid_t Inode::get_best_cap_gid()
-{
- gid_t any = -1;
- for (const auto ci : caps) {
- if (ci.second->latest_gid == uid)
- return uid;
- any = ci.second->latest_gid;
+ const UserPerm& iperm = ci.second->latest_perms;
+ if (!perms) { // we don't have any, take what's present
+ perms = &iperm;
+ } else if (iperm.uid() == uid) {
+ if (iperm.gid() == gid) { // we have the best possible, return
+ return &iperm;
+ }
+ if (perms->uid() != uid) { // take uid > gid every time
+ perms = &iperm;
+ }
+ } else if (perms->uid() != uid && iperm.gid() == gid) {
+ perms = &iperm; // a matching gid is better than nothing
+ }
}
- return any;
+ return perms;
}
bool Inode::have_valid_size()