int Client::get_caps(Inode *in, int need, int want, int *phave, loff_t endoff)
{
+ int r = check_pool_perm(in, need);
+ if (r < 0)
+ return r;
+
while (1) {
if (!in->is_any_caps())
return -ESTALE;
return false;
}
+enum {
+ POOL_CHECKED = 1,
+ POOL_CHECKING = 2,
+ POOL_READ = 4,
+ POOL_WRITE = 8,
+};
+
+int Client::check_pool_perm(Inode *in, int need)
+{
+ if (!cct->_conf->client_check_pool_perm)
+ return 0;
+
+ int64_t pool = in->layout.fl_pg_pool;
+ int have = 0;
+ while (true) {
+ std::map<int64_t, int>::iterator it = pool_perms.find(pool);
+ if (it == pool_perms.end())
+ break;
+ if (it->second == POOL_CHECKING) {
+ // avoid concurrent checkings
+ wait_on_list(waiting_for_pool_perm);
+ } else {
+ have = it->second;
+ assert(have & POOL_CHECKED);
+ break;
+ }
+ }
+
+ if (!have) {
+ pool_perms[pool] = POOL_CHECKING;
+
+ char oid_buf[32];
+ snprintf(oid_buf, sizeof(oid_buf), "%llx.00000000", (unsigned long long)in->ino);
+ object_t oid = oid_buf;
+
+ Mutex lock("Client::check_pool_perm::lock");
+ Cond cond;
+ bool done[2] = {false, false};
+ int rd_ret;
+ int wr_ret;
+
+ ObjectOperation rd_op;
+ rd_op.stat(NULL, (utime_t*)NULL, NULL);
+
+ objecter->mutate(oid, OSDMap::file_to_object_locator(in->layout), rd_op,
+ in->snaprealm->get_snap_context(), ceph_clock_now(cct), 0,
+ new C_SafeCond(&lock, &cond, &done[0], &rd_ret), NULL);
+
+ ObjectOperation wr_op;
+ wr_op.create(true);
+
+ objecter->mutate(oid, OSDMap::file_to_object_locator(in->layout), wr_op,
+ in->snaprealm->get_snap_context(), ceph_clock_now(cct), 0,
+ new C_SafeCond(&lock, &cond, &done[1], &wr_ret), NULL);
+
+ client_lock.Unlock();
+ lock.Lock();
+ while (!done[0] || !done[1])
+ cond.Wait(lock);
+ lock.Unlock();
+ client_lock.Lock();
+
+ if (rd_ret == 0 || rd_ret == -ENOENT)
+ have |= POOL_READ;
+ else if (rd_ret != -EPERM) {
+ ldout(cct, 10) << "check_pool_perm on pool " << pool
+ << " rd_err = " << rd_ret << " wr_err = " << wr_ret << dendl;
+ return rd_ret;
+ }
+
+ if (wr_ret == 0 || wr_ret == -EEXIST)
+ have |= POOL_WRITE;
+ else if (wr_ret != -EPERM) {
+ ldout(cct, 10) << "check_pool_perm on pool " << pool
+ << " rd_err = " << rd_ret << " wr_err = " << wr_ret << dendl;
+ return wr_ret;
+ }
+
+ pool_perms[pool] = have | POOL_CHECKED;
+ signal_cond_list(waiting_for_pool_perm);
+ }
+
+ if ((need & CEPH_CAP_FILE_RD) && !(have & POOL_READ)) {
+ ldout(cct, 10) << "check_pool_perm on pool " << pool
+ << " need " << ccap_string(need) << ", but no read perm" << dendl;
+ return -EPERM;
+ }
+ if ((need & CEPH_CAP_FILE_WR) && !(have & POOL_WRITE)) {
+ ldout(cct, 10) << "check_pool_perm on pool " << pool
+ << " need " << ccap_string(need) << ", but no write perm" << dendl;
+ return -EPERM;
+ }
+
+ return 0;
+}
+
void Client::set_filer_flags(int flags)
{
Mutex::Locker l(client_lock);