From 02d6a148776b831d864b20e6ae37d3e953684517 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Wed, 13 Aug 2008 22:35:33 -0700 Subject: [PATCH] kclient: remove from snaprealm list on cap removal; fix various ceph_remove_cap bugs --- src/kernel/inode.c | 40 ++++++++++++++++++++++++++++------------ src/kernel/mds_client.c | 10 ++++------ src/kernel/super.h | 4 ++-- 3 files changed, 34 insertions(+), 20 deletions(-) diff --git a/src/kernel/inode.c b/src/kernel/inode.c index 0c0dffc463fcb..67f5bc6bb3c73 100644 --- a/src/kernel/inode.c +++ b/src/kernel/inode.c @@ -1124,7 +1124,7 @@ int ceph_get_cap_mds(struct inode *inode) } /* - * caller should hold session s_mutex. + * caller should hold session snap_mutex, s_mutex. * * @fmode can be negative, in which case it is ignored. */ @@ -1146,7 +1146,7 @@ int ceph_add_cap(struct inode *inode, realm = ceph_update_snap_trace(mdsc, snapblob, snapblob+snapblob_len, 0); - + dout(10, "ceph_add_cap on %p mds%d cap %d seq %d\n", inode, session->s_mds, issued, seq); spin_lock(&inode->i_lock); @@ -1243,13 +1243,15 @@ int __ceph_caps_issued(struct ceph_inode_info *ci, int *implemented) } /* - * caller should hold i_lock and session s_mutex. + * caller should hold i_lock, snap_mutex, and session s_mutex. + * returns true if this is the last cap. if so, caller should iput. */ -void __ceph_remove_cap(struct ceph_inode_cap *cap) +int __ceph_remove_cap(struct ceph_inode_cap *cap) { struct ceph_mds_session *session = cap->session; + struct ceph_inode_info *ci = cap->ci; - dout(20, "__ceph_remove_cap %p from %p\n", cap, &cap->ci->vfs_inode); + dout(20, "__ceph_remove_cap %p from %p\n", cap, &ci->vfs_inode); /* remove from session list */ list_del_init(&cap->session_caps); @@ -1260,22 +1262,30 @@ void __ceph_remove_cap(struct ceph_inode_cap *cap) cap->session = 0; cap->mds = -1; /* mark unused */ - if (cap < cap->ci->i_static_caps || - cap >= cap->ci->i_static_caps + STATIC_CAPS) + if (cap < ci->i_static_caps || + cap >= ci->i_static_caps + STATIC_CAPS) kfree(cap); + + if (list_empty(&ci->i_caps)) { + list_del_init(&ci->i_snaprealm_item); + return 1; + } + return 0; } /* - * caller should hold session s_mutex. + * caller should hold snap_mutex and session s_mutex. */ void ceph_remove_cap(struct ceph_inode_cap *cap) { struct inode *inode = &cap->ci->vfs_inode; + int was_last; spin_lock(&inode->i_lock); - __ceph_remove_cap(cap); + was_last = __ceph_remove_cap(cap); spin_unlock(&inode->i_lock); - iput(inode); + if (was_last) + iput(inode); } /* @@ -1459,7 +1469,7 @@ void ceph_put_fmode(struct ceph_inode_info *ci, int fmode) /* - * caller holds s_mutex. + * caller holds s_mutex. NOT snap_mutex. * return value: * 0 - ok * 1 - send the msg back to mds @@ -1649,6 +1659,9 @@ void __ceph_do_pending_vmtruncate(struct inode *inode) dout(10, "__do_pending_vmtruncate %p nothing to do\n", inode); } +/* + * caller hold s_mutex, NOT snap_mutex. + */ void ceph_handle_cap_trunc(struct inode *inode, struct ceph_mds_caps *trunc, struct ceph_mds_session *session) @@ -1701,6 +1714,7 @@ void ceph_handle_cap_export(struct inode *inode, struct ceph_mds_caps *ex, unsigned mseq = le32_to_cpu(ex->migrate_seq); struct ceph_inode_cap *cap = 0, *t; struct list_head *p; + int was_last = 0; dout(10, "handle_cap_export inode %p ci %p mds%d mseq %d\n", inode, ci, mds, mseq); @@ -1724,11 +1738,13 @@ void ceph_handle_cap_export(struct inode *inode, struct ceph_mds_caps *ex, ci->i_cap_exporting_mds = mds; ci->i_cap_exporting_mseq = mseq; ci->i_cap_exporting_issued = cap->issued; - __ceph_remove_cap(cap); + was_last = __ceph_remove_cap(cap); } out: spin_unlock(&inode->i_lock); + if (was_last) + iput(inode); } void ceph_handle_cap_import(struct inode *inode, struct ceph_mds_caps *im, diff --git a/src/kernel/mds_client.c b/src/kernel/mds_client.c index 67a3ab0f2e972..b42f92a333180 100644 --- a/src/kernel/mds_client.c +++ b/src/kernel/mds_client.c @@ -1550,7 +1550,6 @@ void ceph_mdsc_handle_caps(struct ceph_mds_client *mdsc, /* lookup ino */ inode = ceph_find_inode(sb, vino); dout(20, "op %d ino %llx inode %p\n", op, vino.ino, inode); - if (!inode) { dout(10, "i don't have ino %llx, sending release\n", vino.ino); send_cap_ack(mdsc, vino.ino, CEPH_CAP_OP_RELEASE, 0, 0, seq, @@ -1574,8 +1573,8 @@ void ceph_mdsc_handle_caps(struct ceph_mds_client *mdsc, break; case CEPH_CAP_OP_EXPORT: - mutex_unlock(&mdsc->snap_mutex); ceph_handle_cap_export(inode, h, session); + mutex_unlock(&mdsc->snap_mutex); break; case CEPH_CAP_OP_IMPORT: @@ -1615,7 +1614,7 @@ static void __cap_delay_cancel(struct ceph_mds_client *mdsc, /* * called with i_lock, then drops it. - * caller should hold s_mutex. + * caller should hold snap_mutex, s_mutex. * * returns true if we removed the last cap on this inode. */ @@ -1662,8 +1661,7 @@ int __ceph_mdsc_send_cap(struct ceph_mds_client *mdsc, time_warp_seq = ci->i_time_warp_seq; follows = ci->i_snaprealm->cached_context->seq; if (wanted == 0 && !flush_snap) { - __ceph_remove_cap(cap); - removed_last = list_empty(&ci->i_caps); + removed_last = __ceph_remove_cap(cap); if (removed_last && cancel_work) __cap_delay_cancel(mdsc, ci); } @@ -1687,7 +1685,7 @@ int __ceph_mdsc_send_cap(struct ceph_mds_client *mdsc, if (wake) wake_up(&ci->i_cap_wq); - if (wanted == 0 && !flush_snap) + if (removed_last) iput(inode); /* removed cap */ return removed_last; diff --git a/src/kernel/super.h b/src/kernel/super.h index 9b4a430bd5b35..cda488b0ebe02 100644 --- a/src/kernel/super.h +++ b/src/kernel/super.h @@ -199,7 +199,7 @@ struct ceph_inode_frag { int dist[MAX_DIRFRAG_REP]; }; -#define STATIC_CAPS 2 +#define STATIC_CAPS 1 struct ceph_dir_info { u64 nfiles, nsubdirs; @@ -541,7 +541,7 @@ extern int ceph_add_cap(struct inode *inode, int fmode, unsigned issued, unsigned cap, unsigned seq, void *snapblob, int snapblob_len); -extern void __ceph_remove_cap(struct ceph_inode_cap *cap); +extern int __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_get_cap_mds(struct inode *inode); -- 2.39.5