.set_default(2)
.set_flag(Option::FLAG_RUNTIME)
.set_description("interval in seconds for metrics data update.")
- .set_long_description("interval in seconds after which active MDSs send client metrics data to rank 0.")
+ .set_long_description("interval in seconds after which active MDSs send client metrics data to rank 0."),
+
+ Option("mds_dir_max_entries", Option::TYPE_UINT, Option::LEVEL_ADVANCED)
+ .set_default(0)
+ .set_flag(Option::FLAG_RUNTIME)
+ .set_description("maximum number of entries per directory before new creat/links fail")
+ .set_long_description("The maximum number of entries before any new entries are rejected with ENOSPC.")
});
}
cap_acquisition_throttle = g_conf().get_val<uint64_t>("mds_session_cap_acquisition_throttle");
max_caps_throttle_ratio = g_conf().get_val<double>("mds_session_max_caps_throttle_ratio");
caps_throttle_retry_request_timeout = g_conf().get_val<double>("mds_cap_acquisition_throttle_retry_request_timeout");
+ dir_max_entries = g_conf().get_val<uint64_t>("mds_dir_max_entries");
supported_features = feature_bitset_t(CEPHFS_FEATURES_MDS_SUPPORTED);
}
if (changed.count("mds_alternate_name_max")) {
alternate_name_max = g_conf().get_val<Option::size_t>("mds_alternate_name_max");
}
+ if (changed.count("mds_dir_max_entries")) {
+ dir_max_entries = g_conf().get_val<uint64_t>("mds_dir_max_entries");
+ dout(20) << __func__ << " max entries per directory changed to "
+ << dir_max_entries << dendl;
+ }
}
/*
return true;
}
+/**
+ * check whether entries in a dir reached maximum size
+ *
+ */
+bool Server::check_dir_max_entries(MDRequestRef &mdr, CDir *in)
+{
+ const uint64_t size = in->inode->get_projected_inode()->dirstat.nfiles +
+ in->inode->get_projected_inode()->dirstat.nsubdirs;
+ if (dir_max_entries && size >= dir_max_entries) {
+ dout(10) << "entries per dir " << *in << " size exceeds " << dir_max_entries << " (ENOSPC)" << dendl;
+ respond_to_request(mdr, -ENOSPC);
+ return false;
+ }
+ return true;
+}
+
+
CDentry* Server::prepare_stray_dentry(MDRequestRef& mdr, CInode *in)
{
string straydname;
return;
if (!check_fragment_space(mdr, dir))
return;
+ if (!check_dir_max_entries(mdr, dir))
+ return;
if (mdr->dn[0].size() == 1)
mds->locker->create_lock_cache(mdr, diri, &mdr->dir_layout);
CInode *diri = dir->get_inode();
if (!check_access(mdr, diri, MAY_WRITE))
return;
- if (!check_fragment_space(mdr, dn->get_dir()))
+ if (!check_fragment_space(mdr, dir))
+ return;
+ if (!check_dir_max_entries(mdr, dir))
return;
ceph_assert(dn->get_projected_linkage()->is_null());
if (!check_fragment_space(mdr, dir))
return;
+ if (!check_dir_max_entries(mdr, dir))
+ return;
ceph_assert(dn->get_projected_linkage()->is_null());
if (req->get_alternate_name().size() > alternate_name_max) {
return;
if (!check_fragment_space(mdr, dir))
return;
+ if (!check_dir_max_entries(mdr, dir))
+ return;
ceph_assert(dn->get_projected_linkage()->is_null());
if (req->get_alternate_name().size() > alternate_name_max) {
if (!check_fragment_space(mdr, dir))
return;
+
+ if (!check_dir_max_entries(mdr, dir))
+ return;
}
CInode* target_pin = targeti->get_projected_parent_dir()->inode;
if (!check_fragment_space(mdr, destdn->get_dir()))
return;
+ if (!check_dir_max_entries(mdr, destdn->get_dir()))
+ return;
+
if (!check_access(mdr, srci, MAY_WRITE))
return;
}
// some helpers
bool check_fragment_space(MDRequestRef& mdr, CDir *in);
+ bool check_dir_max_entries(MDRequestRef& mdr, CDir *in);
bool check_access(MDRequestRef& mdr, CInode *in, unsigned mask);
bool _check_access(Session *session, CInode *in, unsigned mask, int caller_uid, int caller_gid, int setattr_uid, int setattr_gid);
CDentry *prepare_stray_dentry(MDRequestRef& mdr, CInode *in);
double cap_revoke_eviction_timeout = 0;
uint64_t max_snaps_per_dir = 100;
unsigned delegate_inos_pct = 0;
+ uint64_t dir_max_entries = 0;
DecayCounter recall_throttle;
time last_recall_state;