--- /dev/null
+#!/bin/sh -x
+
+set -e
+
+# multiple intervening snapshots with no modifications, and thus no
+# snapflush client_caps messages. make sure the mds can handle this.
+
+for f in `seq 1 20` ; do
+
+mkdir a
+cat > a/foo &
+mkdir a/.snap/one
+mkdir a/.snap/two
+chmod 777 a/foo
+sync # this might crash the mds
+ps
+rmdir a/.snap/*
+rm a/foo
+rmdir a
+
+done
+
+echo OK
while (p != head_in->client_need_snapflush.end()) {
snapid_t snapid = p->first;
set<client_t>& clients = p->second;
- p++;
+ p++; // be careful, q loop below depends on this
// snapid is the snap inode's ->last
if (follows > snapid)
if (clients.count(client)) {
dout(10) << " doing async NULL snapflush on " << snapid << " from client" << client << dendl;
CInode *sin = mdcache->get_inode(head_in->ino(), snapid);
- if (!sin && head_in->is_multiversion())
- sin = head_in;
- assert(sin);
+ if (!sin) {
+ // hrm, look forward until we find the inode.
+ // (we can only look it up by the last snapid it is valid for)
+ dout(10) << " didn't have " << head_in->ino() << " snapid " << snapid << dendl;
+ for (map<snapid_t, set<client_t> >::iterator q = p; // p is already at next entry
+ q != head_in->client_need_snapflush.end();
+ q++) {
+ dout(10) << " trying snapid " << q->first << dendl;
+ sin = mdcache->get_inode(head_in->ino(), q->first);
+ if (sin) {
+ assert(sin->first <= snapid);
+ break;
+ }
+ dout(10) << " didn't have " << head_in->ino() << " snapid " << q->first << dendl;
+ }
+ if (!sin && head_in->is_multiversion())
+ sin = head_in;
+ assert(sin);
+ }
_do_snap_update(sin, snapid, 0, sin->first - 1, client, NULL, NULL);
head_in->remove_need_snapflush(sin, snapid, client);
}