summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYan, Zheng <zheng.z.yan@intel.com>2013-10-20 17:08:42 +0800
committerYan, Zheng <zheng.z.yan@intel.com>2013-10-20 17:27:49 +0800
commit6ed3ada9e6e34ffc407e0f5f1ffeada9e50a8cf9 (patch)
tree2c036585e584b688038023b2de4bc338054288ee
parent4d3502ba9b310cddcd8325da4b08adee26587143 (diff)
downloadceph-wip-6599.tar.gz
client: fix invalid iterator dereference in Client::trim_caps()wip-6599
trimming inode drops a reference to the inode's parent, it may cause the inode's parent also be trimmed. If the cap iterator 'p' happens to point to the inode's parent and the inode's parent is trimmed, the cap iterator 'p' become invalid. Fix the issue by delaying removing cap from the seesion cap list. (similar to what the kclient does) Signed-off-by: Yan, Zheng <zheng.z.yan@intel.com>
-rw-r--r--src/client/Client.cc19
-rw-r--r--src/client/MetaSession.h4
2 files changed, 18 insertions, 5 deletions
diff --git a/src/client/Client.cc b/src/client/Client.cc
index 20651892c0c..89de94ee6ea 100644
--- a/src/client/Client.cc
+++ b/src/client/Client.cc
@@ -2921,8 +2921,6 @@ void Client::remove_cap(Cap *cap)
i.seq = cap->issue_seq;
i.migrate_seq = cap->mseq;
session->release->caps.push_back(i);
-
- cap->cap_item.remove_myself();
if (in->auth_cap == cap) {
if (in->flushing_cap_item.is_on_list()) {
@@ -2933,7 +2931,13 @@ void Client::remove_cap(Cap *cap)
}
assert(in->caps.count(mds));
in->caps.erase(mds);
- delete cap;
+
+ if (cap == session->s_cap_iterator) {
+ cap->inode = NULL;
+ } else {
+ cap->cap_item.remove_myself();
+ delete cap;
+ }
if (!in->is_any_caps()) {
ldout(cct, 15) << "remove_cap last one, closing snaprealm " << in->snaprealm << dendl;
@@ -2966,7 +2970,7 @@ void Client::trim_caps(MetaSession *s, int max)
xlist<Cap*>::iterator p = s->caps.begin();
while (s->caps.size() > max && !p.end()) {
Cap *cap = *p;
- ++p;
+ s->s_cap_iterator = cap;
Inode *in = cap->inode;
if (in->caps.size() > 1 && cap != in->auth_cap) {
// disposable non-auth cap
@@ -2992,7 +2996,14 @@ void Client::trim_caps(MetaSession *s, int max)
if (all)
trimmed++;
}
+
+ ++p;
+ if (!cap->inode) {
+ cap->cap_item.remove_myself();
+ delete cap;
+ }
}
+ s->s_cap_iterator = NULL;
}
void Client::mark_caps_dirty(Inode *in, int caps)
diff --git a/src/client/MetaSession.h b/src/client/MetaSession.h
index a6cf634c969..d9fcbb881d9 100644
--- a/src/client/MetaSession.h
+++ b/src/client/MetaSession.h
@@ -43,12 +43,14 @@ struct MetaSession {
xlist<MetaRequest*> requests;
xlist<MetaRequest*> unsafe_requests;
+ Cap *s_cap_iterator;
+
MClientCapRelease *release;
MetaSession()
: mds_num(-1), con(NULL),
seq(0), cap_gen(0), cap_renew_seq(0), num_caps(0),
- state(STATE_NEW),
+ state(STATE_NEW), s_cap_iterator(NULL),
release(NULL)
{}
~MetaSession();