diff options
author | Sage Weil <sage@newdream.net> | 2010-04-19 10:15:44 -0700 |
---|---|---|
committer | Sage Weil <sage@newdream.net> | 2010-05-03 10:49:23 -0700 |
commit | 91dee39eebcfb47085c4d457a584b0e9723b6ca0 (patch) | |
tree | 52bdeb4795c3b60b1d23460cada8c813c94fb7a9 /fs/ceph/snap.c | |
parent | c10f5e12bafde7f7a2f9b75d76f7a68d62154e91 (diff) | |
download | op-kernel-dev-91dee39eebcfb47085c4d457a584b0e9723b6ca0.zip op-kernel-dev-91dee39eebcfb47085c4d457a584b0e9723b6ca0.tar.gz |
ceph: fix snap realm splits
The snap realm split was checking i_snap_realm, not the list_head, to
determine if an inode belonged in the new realm. The check always failed,
which meant we always moved the inode, corrupting the old realm's list and
causing various crashes.
Also wait to release old realm reference to avoid possibility of use after
free.
Signed-off-by: Sage Weil <sage@newdream.net>
Diffstat (limited to 'fs/ceph/snap.c')
-rw-r--r-- | fs/ceph/snap.c | 24 |
1 files changed, 14 insertions, 10 deletions
diff --git a/fs/ceph/snap.c b/fs/ceph/snap.c index 2b88126..d5114db 100644 --- a/fs/ceph/snap.c +++ b/fs/ceph/snap.c @@ -869,16 +869,20 @@ skip_inode: continue; ci = ceph_inode(inode); spin_lock(&inode->i_lock); - if (!ci->i_snap_realm) - goto split_skip_inode; - ceph_put_snap_realm(mdsc, ci->i_snap_realm); - spin_lock(&realm->inodes_with_caps_lock); - list_add(&ci->i_snap_realm_item, - &realm->inodes_with_caps); - ci->i_snap_realm = realm; - spin_unlock(&realm->inodes_with_caps_lock); - ceph_get_snap_realm(mdsc, realm); -split_skip_inode: + if (list_empty(&ci->i_snap_realm_item)) { + struct ceph_snap_realm *oldrealm = + ci->i_snap_realm; + + dout(" moving %p to split realm %llx %p\n", + inode, realm->ino, realm); + spin_lock(&realm->inodes_with_caps_lock); + list_add(&ci->i_snap_realm_item, + &realm->inodes_with_caps); + ci->i_snap_realm = realm; + spin_unlock(&realm->inodes_with_caps_lock); + ceph_get_snap_realm(mdsc, realm); + ceph_put_snap_realm(mdsc, oldrealm); + } spin_unlock(&inode->i_lock); iput(inode); } |