When a subtree is freezing, it's no longer possible to acquire new authpins.
This is a problem when a compound request like quiescing a subtree is trying to
acquire authpins for each sub-op. This creates a situation where some quiesce
sub-ops complete with authpins (thereby preventing the tree from becoming
"frozen") and new sub-ops cannot acquire authpins (because the tree is
"freezing"). To circumvent this, allow some authpin requests to proceed if
FLAG_BYPASSFREEZING is set.
Signed-off-by: Patrick Donnelly <pdonnell@redhat.com>
return auth_pins;
}
-bool CDentry::can_auth_pin(int *err_ret) const
+bool CDentry::can_auth_pin(int *err_ret, bool bypassfreezing) const
{
ceph_assert(dir);
- return dir->can_auth_pin(err_ret);
+ return dir->can_auth_pin(err_ret, bypassfreezing);
}
void CDentry::auth_pin(void *by)
void _put() override;
// auth pins
- bool can_auth_pin(int *err_ret=nullptr) const override;
+ bool can_auth_pin(int *err_ret=nullptr, bool bypassfreezing=false) const override;
void auth_pin(void *by) override;
void auth_unpin(void *by) override;
void adjust_nested_auth_pins(int diradj, void *by);
mdcache->mds->queue_waiters(unfreeze_waiters);
}
-bool CDir::can_auth_pin(int *err_ret) const
+bool CDir::can_auth_pin(int *err_ret, bool bypassfreezing) const
{
int err;
if (!is_auth()) {
err = ERR_NOT_AUTH;
- } else if (is_freezing_dir() || is_frozen_dir()) {
+ } else if (is_freezing_dir()) {
+ if (bypassfreezing) {
+ dout(20) << "allowing authpin with freezing" << dendl;
+ err = 0;
+ } else {
+ err = ERR_FRAGMENTING_DIR;
+ }
+ } else if (is_frozen_dir()) {
err = ERR_FRAGMENTING_DIR;
} else {
auto p = is_freezing_or_frozen_tree();
- if (p.first || p.second) {
+ if (p.first && !bypassfreezing) {
+ err = ERR_EXPORTING_TREE;
+ } else if (p.second) {
err = ERR_EXPORTING_TREE;
} else {
err = 0;
void abort_import();
// -- auth pins --
- bool can_auth_pin(int *err_ret=nullptr) const override;
+ bool can_auth_pin(int *err_ret=nullptr, bool bypassfreezing=false) const override;
int get_auth_pins() const { return auth_pins; }
int get_dir_auth_pins() const { return dir_auth_pins; }
void auth_pin(void *who) override;
}
// auth_pins
-bool CInode::can_auth_pin(int *err_ret) const {
+bool CInode::can_auth_pin(int *err_ret, bool bypassfreezing) const {
int err;
if (!is_auth()) {
err = ERR_NOT_AUTH;
- } else if (is_freezing_inode() || is_frozen_inode() || is_frozen_auth_pin()) {
+ } else if (is_freezing_inode()) {
+ if (bypassfreezing) {
+ dout(20) << "allowing authpin with freezing" << dendl;
+ err = 0;
+ } else {
+ err = ERR_EXPORTING_INODE;
+ }
+ } else if (is_frozen_inode() || is_frozen_auth_pin()) {
err = ERR_EXPORTING_INODE;
} else {
if (parent)
mds_authority_t authority() const override;
// -- auth pins --
- bool can_auth_pin(int *err_ret=nullptr) const override;
+ bool can_auth_pin(int *err_ret=nullptr, bool bypassfreezing=false) const override;
void auth_pin(void *by) override;
void auth_unpin(void *by) override;
ERR_FRAGMENTING_DIR,
ERR_EXPORTING_INODE,
};
- virtual bool can_auth_pin(int *err_code=nullptr) const = 0;
+ virtual bool can_auth_pin(int *err_code=nullptr, bool bypassfreezing=false) const = 0;
virtual void auth_pin(void *who) = 0;
virtual void auth_unpin(void *who) = 0;
virtual bool is_frozen() const = 0;
more()->is_ambiguous_auth = false;
}
-bool MDRequestImpl::can_auth_pin(MDSCacheObject *object)
+bool MDRequestImpl::can_auth_pin(MDSCacheObject *object, bool bypassfreezing)
{
- return object->can_auth_pin() ||
+ return object->can_auth_pin(nullptr, bypassfreezing) ||
(is_auth_pinned(object) && has_more() &&
more()->is_freeze_authpin &&
more()->rename_inode == object);
bool freeze_auth_pin(CInode *inode);
void unfreeze_auth_pin(bool clear_inode=false);
void set_remote_frozen_auth_pin(CInode *inode);
- bool can_auth_pin(MDSCacheObject *object);
+ bool can_auth_pin(MDSCacheObject *object, bool bypassfreezing=false);
void drop_local_auth_pins();
void set_ambiguous_auth(CInode *inode);
void clear_ambiguous_auth();
list<MDSCacheObject*> objects;
CInode *auth_pin_freeze = NULL;
bool nonblocking = mdr->peer_request->is_nonblocking();
+ bool bypassfreezing = mdr->peer_request->is_bypassfreezing();
bool fail = false, wouldblock = false, readonly = false;
ref_t<MMDSPeerRequest> reply;
+ dout(15) << " nonblocking=" << nonblocking
+ << " bypassfreezing=" << bypassfreezing << dendl;
+
if (mdcache->is_readonly()) {
dout(10) << " read-only FS" << dendl;
readonly = true;
}
if (mdr->is_auth_pinned(obj))
continue;
- if (!mdr->can_auth_pin(obj)) {
+ if (!mdr->can_auth_pin(obj, bypassfreezing)) {
if (nonblocking) {
dout(10) << " can't auth_pin (freezing?) " << *obj << " nonblocking" << dendl;
fail = true;
static constexpr unsigned FLAG_INTERRUPTED = 1<<5;
static constexpr unsigned FLAG_NOTIFYBLOCKING = 1<<6;
static constexpr unsigned FLAG_REQBLOCKED = 1<<7;
+ static constexpr unsigned FLAG_BYPASSFREEZING = 1<<8;
// for locking
__u16 lock_type; // lock object type
void clear_notify_blocking() const { flags &= ~FLAG_NOTIFYBLOCKING; }
bool is_req_blocked() const { return (flags & FLAG_REQBLOCKED); }
void mark_req_blocked() { flags |= FLAG_REQBLOCKED; }
+ bool is_bypassfreezing() const { return (flags & FLAG_BYPASSFREEZING); }
+ void mark_bypassfreezing() { flags |= FLAG_BYPASSFREEZING; }
void set_lock_type(int t) { lock_type = t; }
const ceph::buffer::list& get_lock_data() const { return inode_export; }