- fix readdir vs fragment race by keeping a separate frag pos, and ignoring dentries below it
mds
-- fix file recovery
- - disallow access until file is recovered?
- add an up:shadow mode?
- tail the mds log as it is written
- periodically check head so that we trim, too
#else
/*
- * crappy slow implementation that uses a pthreads mutex.
+ * crappy slow implementation that uses a pthreads spinlock.
*/
#include "common/Spinlock.h"
lock->set_state(LOCK_SYNC); // might have been lock, previously
}
}
+ void choose_lock_states() {
+ int issued = get_caps_issued();
+ if (is_auth() && (issued & CEPH_CAP_ANY_EXCL))
+ try_choose_loner();
+ choose_lock_state(&filelock, issued);
+ choose_lock_state(&authlock, issued);
+ choose_lock_state(&xattrlock, issued);
+ choose_lock_state(&linklock, issued);
+ }
int count_nonstale_caps() {
int n = 0;
} else {
cap = add_client_cap(client, session);
cap->set_wanted(icr.wanted);
- cap->issue(icr.issued);
+ cap->issue_norevoke(icr.issued);
}
cap->set_cap_id(icr.cap_id);
cap->set_last_issue_stamp(g_clock.recent_now());
Capability* Locker::issue_new_caps(CInode *in,
int mode,
Session *session,
- SnapRealm *realm)
+ SnapRealm *realm,
+ bool is_replay)
{
dout(7) << "issue_new_caps for mode " << mode << " on " << *in << dendl;
bool is_new;
+ // if replay, try to reconnect cap, and otherwise do nothing.
+ if (is_replay) {
+ mds->mdcache->try_reconnect_cap(in, session);
+ return 0;
+ }
+
// my needs
assert(session->inst.name.is_client());
int my_client = session->inst.name.num();
// -- file i/o --
public:
version_t issue_file_data_version(CInode *in);
- Capability* issue_new_caps(CInode *in, int mode, Session *session, SnapRealm *conrealm=0);
+ Capability* issue_new_caps(CInode *in, int mode, Session *session, SnapRealm *conrealm, bool is_replay);
bool issue_caps(CInode *in, Capability *only_cap=0);
void issue_truncate(CInode *in);
void revoke_stale_caps(Session *session);
CInode *in = p->first;
p++;
- int issued = in->get_caps_issued();
- if (in->is_auth() &&
- (issued & CEPH_CAP_ANY_EXCL))
- in->try_choose_loner();
- in->choose_lock_state(&in->filelock, issued);
- in->choose_lock_state(&in->authlock, issued);
- in->choose_lock_state(&in->xattrlock, issued);
- in->choose_lock_state(&in->linklock, issued);
- dout(15) << " issued " << ccap_string(issued)
- << " chose lock states on " << *in << dendl;
+ in->choose_lock_states();
+ dout(15) << " chose lock states on " << *in << dendl;
SnapRealm *realm = in->find_snaprealm();
do_cap_import(session, in, cap);
}
+void MDCache::try_reconnect_cap(CInode *in, Session *session)
+{
+ int client = session->get_client();
+ ceph_mds_cap_reconnect *rc = get_replay_cap_reconnect(in->ino(), client);
+ if (rc) {
+ in->reconnect_cap(client, *rc, session);
+ dout(10) << "try_reconnect_cap client" << client
+ << " reconnect wanted " << ccap_string(rc->wanted)
+ << " issue " << ccap_string(rc->issued)
+ << " on " << *in << dendl;
+ remove_replay_cap_reconnect(in->ino(), client);
+
+ in->choose_lock_states();
+ dout(15) << " chose lock states on " << *in << dendl;
+ }
+}
+
+
// -------
// cap imports and delayed snap parent opens
class Logger;
class MDS;
+class Session;
class Migrator;
class Renamer;
void send_snaps(map<int,MClientSnap*>& splits);
void rejoin_import_cap(CInode *in, int client, ceph_mds_cap_reconnect& icr, int frommds);
void finish_snaprealm_reconnect(int client, SnapRealm *realm, snapid_t seq);
+ void try_reconnect_cap(CInode *in, Session *session);
// cap imports. delayed snap parent opens.
// realm inode -> client -> cap inodes needing to split to this realm
// finish any triggered contexts
static bool finishing = false;
- if (!finishing && finished_queue.size()) {
- dout(7) << "mds has " << finished_queue.size() << " queued contexts" << dendl;
- dout(10) << finished_queue << dendl;
- list<Context*> ls;
- ls.splice(ls.begin(), finished_queue);
- assert(finished_queue.empty());
- finishing = true;
- finish_contexts(ls);
- finishing = false;
- } else {
+ if (!finishing) {
+ while (finished_queue.size()) {
+ dout(7) << "mds has " << finished_queue.size() << " queued contexts" << dendl;
+ dout(10) << finished_queue << dendl;
+ finishing = true;
+ finish_contexts(finished_queue);
+ finishing = false;
+ }
+
// done with all client replayed requests?
- if (!finishing &&
- is_clientreplay() &&
+ if (is_clientreplay() &&
mdcache->is_open() &&
waiting_for_replay.empty() &&
want_state == MDSMap::STATE_CLIENTREPLAY) {
void Server::reply_request(MDRequest *mdr, MClientReply *reply, CInode *tracei, CDentry *tracedn)
{
MClientRequest *req = mdr->client_request;
- int client = mdr->get_client();
dout(10) << "reply_request " << reply->get_result()
<< " (" << strerror(-reply->get_result())
if (!did_early_reply && // don't issue leases if we sent an earlier reply already
(tracei || tracedn)) {
if (is_replay) {
- // replay ops don't get a trace.
- // reconnect cap to created inode?
- if (tracei) {
- ceph_mds_cap_reconnect *rc = mdcache->get_replay_cap_reconnect(tracei->ino(), client);
- if (rc) {
- Capability *cap = tracei->get_client_cap(client);
- // we should only have the cap reconnect for ONE client, and from ourselves.
- dout(10) << " incorporating cap reconnect wanted " << ccap_string(rc->wanted)
- << " issue " << ccap_string(rc->issued) << " on " << *tracei << dendl;
- cap->set_wanted(rc->wanted);
- cap->issue_norevoke(rc->issued);
- cap->set_cap_id(rc->cap_id);
- mdcache->remove_replay_cap_reconnect(tracei->ino(), client);
- }
- }
+ if (tracei)
+ mdcache->try_reconnect_cap(tracei, session);
} else {
// include metadata in reply
set_trace_dist(session, reply, tracei, tracedn, snapid, dentry_wanted);
if (cur->is_file() || cur->is_dir()) {
if (mdr->snapid == CEPH_NOSNAP) {
// register new cap
- Capability *cap = mds->locker->issue_new_caps(cur, cmode, mdr->session);
- dout(12) << "open issued caps " << ccap_string(cap->pending())
- << " for " << req->get_orig_source()
- << " on " << *cur << dendl;
+ Capability *cap = mds->locker->issue_new_caps(cur, cmode, mdr->session, 0, req->is_replay());
+ if (cap)
+ dout(12) << "open issued caps " << ccap_string(cap->pending())
+ << " for " << req->get_orig_source()
+ << " on " << *cur << dendl;
} else {
int caps = ceph_caps_for_mode(cmode);
dout(12) << "open issued IMMUTABLE SNAP caps " << ccap_string(caps)
le->metablob.add_primary_dentry(dn, true, in);
// do the open
- mds->locker->issue_new_caps(in, cmode, mdr->session, realm);
+ mds->locker->issue_new_caps(in, cmode, mdr->session, realm, req->is_replay());
in->authlock.set_state(LOCK_EXCL);
in->xattrlock.set_state(LOCK_EXCL);
// do the open
SnapRealm *realm = in->find_snaprealm();
- mds->locker->issue_new_caps(in, cmode, mdr->session, realm);
+ mds->locker->issue_new_caps(in, cmode, mdr->session, realm, mdr->client_request->is_replay());
// make sure ino gets into the journal
le->metablob.add_opened_ino(in->ino());
// issue a cap on the directory
int cmode = CEPH_FILE_MODE_RDWR;
- Capability *cap = mds->locker->issue_new_caps(newi, cmode, mdr->session, realm);
- cap->set_wanted(0);
-
- // put locks in excl mode
- newi->filelock.set_state(LOCK_EXCL);
- newi->authlock.set_state(LOCK_EXCL);
- newi->xattrlock.set_state(LOCK_EXCL);
- cap->issue_norevoke(CEPH_CAP_AUTH_EXCL|CEPH_CAP_AUTH_SHARED|
- CEPH_CAP_XATTR_EXCL|CEPH_CAP_XATTR_SHARED);
+ Capability *cap = mds->locker->issue_new_caps(newi, cmode, mdr->session, realm, req->is_replay());
+ if (cap) {
+ cap->set_wanted(0);
+
+ // put locks in excl mode
+ newi->filelock.set_state(LOCK_EXCL);
+ newi->authlock.set_state(LOCK_EXCL);
+ newi->xattrlock.set_state(LOCK_EXCL);
+ cap->issue_norevoke(CEPH_CAP_AUTH_EXCL|CEPH_CAP_AUTH_SHARED|
+ CEPH_CAP_XATTR_EXCL|CEPH_CAP_XATTR_SHARED);
+ }
// make sure this inode gets into the journal
le->metablob.add_opened_ino(newi->ino());
mdsmap.is_stopped())
mon->messenger->send_message(new MGenericMessage(CEPH_MSG_SHUTDOWN),
mon->monmap->get_inst(mon->whoami));
+
+ tick();
}