struct ceph_dentry_info *di;
struct ceph_mds_session *session;
int valid = 0;
- u64 gen;
+ u32 gen;
unsigned long ttl;
spin_lock(&dentry->d_lock);
}
/*
- * caller shoudl hold session s_mutex.
+ * caller should hold session s_mutex.
+ *
+ * @fmode can be negative, in which case it is ignored.
*/
-struct ceph_inode_cap *ceph_add_cap(struct inode *inode,
- struct ceph_mds_session *session,
- int fmode,
- u32 issued, u32 seq)
+int ceph_add_cap(struct inode *inode,
+ struct ceph_mds_session *session,
+ int fmode, unsigned issued,
+ unsigned seq, unsigned mseq)
{
int mds = session->s_mds;
struct ceph_inode_info *ci = ceph_inode(inode);
spin_unlock(&inode->i_lock);
new_cap = kmalloc(sizeof(*cap), GFP_NOFS);
if (new_cap == 0)
- return ERR_PTR(-ENOMEM);
+ return -ENOMEM;
spin_lock(&inode->i_lock);
}
}
is_new = 1; /* grab inode later */
cap->issued = cap->implemented = 0;
cap->mds = mds;
- cap->seq = 0;
cap->flags = 0;
cap->ci = ci;
cap->session = session;
list_add(&cap->session_caps, &session->s_caps);
session->s_nr_caps++;
+
+ /* clear out old exporting info? */
+ if (ci->i_cap_exporting_mds == mds) {
+ ci->i_cap_exporting_issued = 0;
+ ci->i_cap_exporting_mseq = 0;
+ ci->i_cap_exporting_mds = -1;
+ }
}
dout(10, "add_cap inode %p (%llx) got cap %xh now %xh seq %d from %d\n",
cap->issued |= issued;
cap->implemented |= issued;
cap->seq = seq;
+ cap->mseq = mseq;
cap->gen = session->s_cap_gen;
- __ceph_get_fmode(ci, fmode);
+ if (fmode >= 0)
+ __ceph_get_fmode(ci, fmode);
spin_unlock(&inode->i_lock);
if (is_new)
igrab(inode);
- return cap;
+ return 0;
}
int __ceph_caps_issued(struct ceph_inode_info *ci)
int have = 0;
struct ceph_inode_cap *cap;
struct list_head *p;
- u64 gen;
+ u32 gen;
unsigned long ttl;
list_for_each(p, &ci->i_caps) {
if (cap->gen < gen || time_after_eq(jiffies, ttl)) {
dout(30, "__ceph_caps_issued %p cap %p issued %d "
- "but STALE (gen %llu vs %llu)\n", &ci->vfs_inode,
+ "but STALE (gen %u vs %u)\n", &ci->vfs_inode,
cap, cap->issued, cap->gen, gen);
continue;
}
dout(10, "__do_pending_vmtruncate %p nothing to do\n", inode);
}
-int ceph_handle_cap_trunc(struct inode *inode, struct ceph_mds_file_caps *trunc,
- struct ceph_mds_session *session)
+void ceph_handle_cap_trunc(struct inode *inode,
+ struct ceph_mds_file_caps *trunc,
+ struct ceph_mds_session *session)
{
struct ceph_inode_info *ci = ceph_inode(inode);
int mds = session->s_mds;
if (queue_trunc)
queue_work(ceph_client(inode->i_sb)->trunc_wq,
&ci->i_vmtruncate_work);
- return 0;
}
+void ceph_handle_cap_export(struct inode *inode, struct ceph_mds_file_caps *ex,
+ struct ceph_mds_session *session)
+{
+ struct ceph_inode_info *ci = ceph_inode(inode);
+ int mds = session->s_mds;
+ unsigned mseq = le32_to_cpu(ex->migrate_seq);
+ struct ceph_inode_cap *cap = 0, *t;
+ struct list_head *p;
+
+ dout(10, "handle_cap_export inode %p ci %p mds%d mseq %d\n",
+ inode, ci, mds, mseq);
+
+ spin_lock(&inode->i_lock);
+
+ /* make sure we haven't seen a higher mseq */
+ list_for_each(p, &ci->i_caps) {
+ t = list_entry(p, struct ceph_inode_cap, ci_caps);
+ if (t->mseq > mseq) {
+ dout(10, " higher mseq on cap from mds%d\n",
+ t->session->s_mds);
+ goto out;
+ }
+ if (t->session->s_mds == mds)
+ cap = t;
+ }
+
+ if (cap) {
+ /* make note, and remove */
+ ci->i_cap_exporting_mds = mds;
+ ci->i_cap_exporting_mseq = mseq;
+ ci->i_cap_exporting_issued = cap->issued;
+ __ceph_remove_cap(cap);
+ }
+
+out:
+ spin_unlock(&inode->i_lock);
+}
+
+void ceph_handle_cap_import(struct inode *inode, struct ceph_mds_file_caps *im,
+ struct ceph_mds_session *session)
+{
+ struct ceph_inode_info *ci = ceph_inode(inode);
+ int mds = session->s_mds;
+ unsigned issued = le32_to_cpu(im->caps);
+ unsigned seq = le32_to_cpu(im->seq);
+ unsigned mseq = le32_to_cpu(im->migrate_seq);
+
+ if (ci->i_cap_exporting_mds >= 0 &&
+ ci->i_cap_exporting_mseq < mseq) {
+ dout(10, "handle_cap_import inode %p ci %p mds%d mseq %d"
+ " - cleared exporting from mds%d\n",
+ inode, ci, mds, mseq,
+ ci->i_cap_exporting_mds);
+ ci->i_cap_exporting_issued = 0;
+ ci->i_cap_exporting_mseq = 0;
+ ci->i_cap_exporting_mds = -1;
+ } else {
+ dout(10, "handle_cap_import inode %p ci %p mds%d mseq %d\n",
+ inode, ci, mds, mseq);
+ }
+
+ ceph_add_cap(inode, session, -1, issued, seq, mseq);
+}
+
+
static void __take_cap_refs(struct ceph_inode_info *ci, int got)
{
if (got & CEPH_CAP_RD)
int mds; /* -1 if not used */
int issued; /* latest, from the mds */
int implemented; /* what we've implemneted (for tracking revocation) */
- u64 seq, gen;
+ u32 seq, mseq, gen;
int flags; /* stale, etc.? */
struct ceph_inode_info *ci;
struct list_head ci_caps; /* per-ci caplist */
int i_lease_mask;
struct ceph_mds_session *i_lease_session;
long unsigned i_lease_ttl; /* jiffies */
- u64 i_lease_gen;
+ u32 i_lease_gen;
struct list_head i_lease_item; /* mds session list */
struct rb_root i_fragtree;
wait_queue_head_t i_cap_wq;
unsigned long i_hold_caps_until; /* jiffies */
struct list_head i_cap_delay_list;
+ int i_cap_exporting_mds;
+ unsigned i_cap_exporting_mseq;
+ unsigned i_cap_exporting_issued;
int i_nr_by_mode[CEPH_FILE_MODE_NUM];
loff_t i_max_size; /* size authorized by mds */
struct ceph_dentry_info {
struct dentry *dentry;
struct ceph_mds_session *lease_session;
- u64 lease_gen;
+ u32 lease_gen;
struct list_head lease_item; /* mds session list */
};
extern int ceph_inode_lease_valid(struct inode *inode, int mask);
extern int ceph_dentry_lease_valid(struct dentry *dentry);
-extern struct ceph_inode_cap *ceph_add_cap(struct inode *inode,
- struct ceph_mds_session *session,
- int fmode,
- u32 cap, u32 seq);
+extern int ceph_add_cap(struct inode *inode,
+ struct ceph_mds_session *session,
+ int fmode, unsigned issued,
+ unsigned cap, unsigned seq);
extern void __ceph_remove_cap(struct ceph_inode_cap *cap);
extern void ceph_remove_cap(struct ceph_inode_cap *cap);
extern void ceph_remove_all_caps(struct ceph_inode_info *ci);
extern int ceph_handle_cap_grant(struct inode *inode,
struct ceph_mds_file_caps *grant,
struct ceph_mds_session *session);
-extern int ceph_handle_cap_trunc(struct inode *inode,
- struct ceph_mds_file_caps *grant,
- struct ceph_mds_session *session);
+extern void ceph_handle_cap_trunc(struct inode *inode,
+ struct ceph_mds_file_caps *trunc,
+ struct ceph_mds_session *session);
+extern void ceph_handle_cap_export(struct inode *inode,
+ struct ceph_mds_file_caps *ex,
+ struct ceph_mds_session *session);
+extern void ceph_handle_cap_import(struct inode *inode,
+ struct ceph_mds_file_caps *im,
+ struct ceph_mds_session *session);
extern int ceph_get_cap_refs(struct ceph_inode_info *ci, int need, int want, int *got, loff_t offset);
extern void ceph_take_cap_refs(struct ceph_inode_info *ci, int got);
extern void ceph_put_cap_refs(struct ceph_inode_info *ci, int had);