1
0
Fork 0

ceph: throw out dirty caps metadata, data on session teardown

The remove_session_caps() helper is called when an MDS closes out our
session (either normally, or as a result of a failed reconnect), and when
we tear down state for umount.  If we remove the last cap, and there are
no cap migrations in progress, then there is little hope of us flushing
out that data to the mds (without heroic efforts to reconnect and flush).

So, to avoid leaving inodes pinned (due to dirty state) and crashing after
umount, throw out dirty caps state and unpin the inodes.  Print a warning
to the console so we know something was lost.

NOTE: Although we drop wrbuffer refs, we don't actually mark pages clean;
maybe a truncate should be queued?

Signed-off-by: Sage Weil <sage@newdream.net>
hifive-unleashed-5.1
Sage Weil 2010-05-10 16:12:25 -07:00
parent 7e70f0ed9f
commit 6c99f2545d
1 changed files with 41 additions and 3 deletions

View File

@ -799,12 +799,49 @@ out:
}
static int remove_session_caps_cb(struct inode *inode, struct ceph_cap *cap,
void *arg)
void *arg)
{
struct ceph_inode_info *ci = ceph_inode(inode);
int drop = 0;
dout("removing cap %p, ci is %p, inode is %p\n",
cap, ci, &ci->vfs_inode);
ceph_remove_cap(cap);
spin_lock(&inode->i_lock);
__ceph_remove_cap(cap);
if (!__ceph_is_any_real_caps(ci)) {
struct ceph_mds_client *mdsc =
&ceph_sb_to_client(inode->i_sb)->mdsc;
spin_lock(&mdsc->cap_dirty_lock);
if (!list_empty(&ci->i_dirty_item)) {
pr_info(" dropping dirty %s state for %p %lld\n",
ceph_cap_string(ci->i_dirty_caps),
inode, ceph_ino(inode));
ci->i_dirty_caps = 0;
list_del_init(&ci->i_dirty_item);
drop = 1;
}
if (!list_empty(&ci->i_flushing_item)) {
pr_info(" dropping dirty+flushing %s state for %p %lld\n",
ceph_cap_string(ci->i_flushing_caps),
inode, ceph_ino(inode));
ci->i_flushing_caps = 0;
list_del_init(&ci->i_flushing_item);
mdsc->num_cap_flushing--;
drop = 1;
}
if (drop && ci->i_wrbuffer_ref) {
pr_info(" dropping dirty data for %p %lld\n",
inode, ceph_ino(inode));
ci->i_wrbuffer_ref = 0;
ci->i_wrbuffer_ref_head = 0;
drop++;
}
spin_unlock(&mdsc->cap_dirty_lock);
}
spin_unlock(&inode->i_lock);
while (drop--)
iput(inode);
return 0;
}
@ -816,6 +853,7 @@ static void remove_session_caps(struct ceph_mds_session *session)
dout("remove_session_caps on %p\n", session);
iterate_session_caps(session, remove_session_caps_cb, NULL);
BUG_ON(session->s_nr_caps > 0);
BUG_ON(!list_empty(&session->s_cap_flushing));
cleanup_cap_releases(session);
}
@ -1281,7 +1319,7 @@ retry:
len += 1 + temp->d_name.len;
temp = temp->d_parent;
if (temp == NULL) {
pr_err("build_path_dentry corrupt dentry %p\n", dentry);
pr_err("build_path corrupt dentry %p\n", dentry);
return ERR_PTR(-EINVAL);
}
}