diff options
author | Sage Weil <sage@newdream.net> | 2010-02-16 14:39:45 -0500 |
---|---|---|
committer | Sage Weil <sage@newdream.net> | 2010-02-17 13:02:47 -0500 |
commit | 7c1332b8cb5b27656cf6ab1f5fe808a8eb8bb2c0 (patch) | |
tree | f990ab6b339a88896f41a6b3541d0676684c935d /fs/ceph/super.h | |
parent | 85ccce43a3fc15a40ded6ae1603e3f68a17f4d24 (diff) |
ceph: fix iterate_caps removal race
We need to be able to iterate over all caps on a session with a
possibly slow callback on each cap. To allow this, we used to
prevent cap reordering while we were iterating. However, we were
not safe from races with removal: removing the 'next' cap would
make the next pointer from list_for_each_entry_safe be invalid,
and cause a lock up or similar badness.
Instead, we keep an iterator pointer in the session pointing to
the current cap. As before, we avoid reordering. For removal,
if the cap isn't the current cap we are iterating over, we are
fine. If it is, we clear cap->ci (to mark the cap as pending
removal) but leave it in the session list. In iterate_caps, we
can safely finish removal and get the next cap pointer.
While we're at it, clean up put_cap to not take a cap reservation
context, as it was never used.
Signed-off-by: Sage Weil <sage@newdream.net>
Diffstat (limited to 'fs/ceph/super.h')
-rw-r--r-- | fs/ceph/super.h | 6 |
1 files changed, 3 insertions, 3 deletions
diff --git a/fs/ceph/super.h b/fs/ceph/super.h index 3b5faf9980f8..384f0e2e7c68 100644 --- a/fs/ceph/super.h +++ b/fs/ceph/super.h | |||
@@ -795,15 +795,15 @@ extern int ceph_add_cap(struct inode *inode, | |||
795 | int fmode, unsigned issued, unsigned wanted, | 795 | int fmode, unsigned issued, unsigned wanted, |
796 | unsigned cap, unsigned seq, u64 realmino, int flags, | 796 | unsigned cap, unsigned seq, u64 realmino, int flags, |
797 | struct ceph_cap_reservation *caps_reservation); | 797 | struct ceph_cap_reservation *caps_reservation); |
798 | extern void __ceph_remove_cap(struct ceph_cap *cap, | 798 | extern void __ceph_remove_cap(struct ceph_cap *cap); |
799 | struct ceph_cap_reservation *ctx); | ||
800 | static inline void ceph_remove_cap(struct ceph_cap *cap) | 799 | static inline void ceph_remove_cap(struct ceph_cap *cap) |
801 | { | 800 | { |
802 | struct inode *inode = &cap->ci->vfs_inode; | 801 | struct inode *inode = &cap->ci->vfs_inode; |
803 | spin_lock(&inode->i_lock); | 802 | spin_lock(&inode->i_lock); |
804 | __ceph_remove_cap(cap, NULL); | 803 | __ceph_remove_cap(cap); |
805 | spin_unlock(&inode->i_lock); | 804 | spin_unlock(&inode->i_lock); |
806 | } | 805 | } |
806 | extern void ceph_put_cap(struct ceph_cap *cap); | ||
807 | 807 | ||
808 | extern void ceph_queue_caps_release(struct inode *inode); | 808 | extern void ceph_queue_caps_release(struct inode *inode); |
809 | extern int ceph_write_inode(struct inode *inode, int unused); | 809 | extern int ceph_write_inode(struct inode *inode, int unused); |