CEPH_CAP_OP_FLUSHSNAP, /* client->mds flush snapped metadata */
CEPH_CAP_OP_FLUSHSNAP_ACK, /* mds->client flushed snapped metadata */
CEPH_CAP_OP_RELEASE, /* client->mds release (clean) cap */
+ CEPH_CAP_OP_RENEW, /* client->mds renewal request */
};
static inline const char *ceph_cap_op_name(int op)
case CEPH_CAP_OP_FLUSHSNAP: return "flushsnap";
case CEPH_CAP_OP_FLUSHSNAP_ACK: return "flushsnap_ack";
case CEPH_CAP_OP_RELEASE: return "release";
+ case CEPH_CAP_OP_RENEW: return "renew";
default: return "???";
}
}
#define CEPH_MDS_LEASE_RENEW 3 /* client <-> mds */
#define CEPH_MDS_LEASE_REVOKE_ACK 4 /* client -> mds */
+static inline const char *ceph_lease_op_name(int o)
+{
+ switch (o) {
+ case CEPH_MDS_LEASE_REVOKE: return "revoke";
+ case CEPH_MDS_LEASE_RELEASE: return "release";
+ case CEPH_MDS_LEASE_RENEW: return "renew";
+ case CEPH_MDS_LEASE_REVOKE_ACK: return "revoke_ack";
+ default: return "???";
+ }
+}
+
struct ceph_mds_lease {
__u8 action;
__le16 mask;
struct ceph_vino vino;
int mask;
struct qstr dname;
+ int release = 0;
if (le32_to_cpu(msg->hdr.src.name.type) != CEPH_ENTITY_TYPE_MDS)
return;
/* lookup inode */
inode = ceph_find_inode(sb, vino);
- dout(20, "handle_lease action is %d, mask %d, ino %llx %p\n", h->action,
- mask, vino.ino, inode);
+ dout(20, "handle_lease '%s', mask %d, ino %llx %p\n",
+ ceph_lease_op_name(h->action), mask, vino.ino, inode);
if (inode == NULL) {
dout(10, "handle_lease no inode %llx\n", vino.ino);
goto release;
}
-
- BUG_ON(h->action != CEPH_MDS_LEASE_REVOKE); /* for now */
-
- /* inode */
ci = ceph_inode(inode);
/* dentry */
- if (mask & CEPH_LOCK_DN) {
- parent = d_find_alias(inode);
- if (!parent) {
- dout(10, "no parent dentry on inode %p\n", inode);
- WARN_ON(1);
- goto release; /* hrm... */
- }
- dname.hash = full_name_hash(dname.name, dname.len);
- dentry = d_lookup(parent, &dname);
- dput(parent);
- if (!dentry)
- goto release;
- di = ceph_dentry(dentry);
+ parent = d_find_alias(inode);
+ if (!parent) {
+ dout(10, "no parent dentry on inode %p\n", inode);
+ WARN_ON(1);
+ goto release; /* hrm... */
+ }
+ dname.hash = full_name_hash(dname.name, dname.len);
+ dentry = d_lookup(parent, &dname);
+ dput(parent);
+ if (!dentry)
+ goto release;
+
+ spin_lock(&dentry->d_lock);
+ di = ceph_dentry(dentry);
+ switch (h->action) {
+ case CEPH_MDS_LEASE_REVOKE:
if (di && di->lease_session == session) {
h->seq = cpu_to_le32(di->lease_seq);
- revoke_dentry_lease(dentry);
+ __drop_dentry_lease(dentry);
}
- dput(dentry);
+ release = 1;
+ break;
+
+ case CEPH_MDS_LEASE_RENEW:
+ if (di && di->lease_session == session &&
+ di->lease_gen == session->s_cap_gen) {
+ unsigned long duration =
+ le32_to_cpu(h->duration_ms) * HZ / 1000;
+
+ di->lease_seq = le32_to_cpu(h->seq);
+ dentry->d_time = le64_to_cpu(h->renew_start) +
+ duration;
+ di->renew_after = le64_to_cpu(h->renew_start) +
+ (duration >> 1);
+ }
+ break;
}
+ spin_unlock(&dentry->d_lock);
+ dput(dentry);
+
+ if (!release)
+ goto out;
release:
- iput(inode);
/* let's just reuse the same message */
h->action = CEPH_MDS_LEASE_REVOKE_ACK;
ceph_msg_get(msg);
ceph_send_msg_mds(mdsc, msg, mds);
+
+out:
+ iput(inode);
mutex_unlock(&session->s_mutex);
ceph_put_mds_session(session);
return;
#include "msg/Message.h"
-static const char *get_lease_action_name(int a) {
- switch (a) {
- case CEPH_MDS_LEASE_REVOKE: return "revoke";
- case CEPH_MDS_LEASE_RELEASE: return "release";
- case CEPH_MDS_LEASE_RENEW: return "renew";
- case CEPH_MDS_LEASE_REVOKE_ACK: return "revoke ack";
- default: assert(0); return 0;
- }
-}
-
-
struct MClientLease : public Message {
struct ceph_mds_lease h;
nstring dname;
const char *get_type_name() { return "client_lease"; }
void print(ostream& out) {
- out << "client_lease(a=" << get_lease_action_name(get_action())
+ out << "client_lease(a=" << ceph_lease_op_name(get_action())
<< " seq " << get_seq()
<< " mask " << get_mask();
out << " " << get_ino();