aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSage Weil <sage@newdream.net>2010-03-16 16:39:28 -0400
committerSage Weil <sage@newdream.net>2010-03-23 10:46:53 -0400
commitcdc2ce056a3620139056b60ad7f6d355ad13f445 (patch)
tree1aed7f66612d13beeeec6e2c191f19eff44d1054
parent4ea0043a29c82ca52ca54728d837314563bec574 (diff)
ceph: fix session locking in handle_caps, ceph_check_caps
Passing a session pointer to ceph_check_caps() used to mean it would leave the session mutex locked. That wasn't always possible if it wasn't passed CHECK_CAPS_AUTHONLY. If could unlock the passed session and lock a differet session mutex, which was clearly wrong, and also emitted a warning when it a racing CPU retook it and we did an unlock from the wrong context. This was only a problem when there was more than one MDS. First, make ceph_check_caps unconditionally drop the session mutex, so that it is free to lock other sessions as needed. Then adjust the one caller that passes in a session (handle_cap_grant) accordingly. Signed-off-by: Sage Weil <sage@newdream.net>
-rw-r--r--fs/ceph/caps.c14
1 files changed, 9 insertions, 5 deletions
diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c
index 726c8d445995..782848632e81 100644
--- a/fs/ceph/caps.c
+++ b/fs/ceph/caps.c
@@ -1407,6 +1407,7 @@ static int try_nonblocking_invalidate(struct inode *inode)
1407 */ 1407 */
1408void ceph_check_caps(struct ceph_inode_info *ci, int flags, 1408void ceph_check_caps(struct ceph_inode_info *ci, int flags,
1409 struct ceph_mds_session *session) 1409 struct ceph_mds_session *session)
1410 __releases(session->s_mutex)
1410{ 1411{
1411 struct ceph_client *client = ceph_inode_to_client(&ci->vfs_inode); 1412 struct ceph_client *client = ceph_inode_to_client(&ci->vfs_inode);
1412 struct ceph_mds_client *mdsc = &client->mdsc; 1413 struct ceph_mds_client *mdsc = &client->mdsc;
@@ -1414,7 +1415,6 @@ void ceph_check_caps(struct ceph_inode_info *ci, int flags,
1414 struct ceph_cap *cap; 1415 struct ceph_cap *cap;
1415 int file_wanted, used; 1416 int file_wanted, used;
1416 int took_snap_rwsem = 0; /* true if mdsc->snap_rwsem held */ 1417 int took_snap_rwsem = 0; /* true if mdsc->snap_rwsem held */
1417 int drop_session_lock = session ? 0 : 1;
1418 int issued, implemented, want, retain, revoking, flushing = 0; 1418 int issued, implemented, want, retain, revoking, flushing = 0;
1419 int mds = -1; /* keep track of how far we've gone through i_caps list 1419 int mds = -1; /* keep track of how far we've gone through i_caps list
1420 to avoid an infinite loop on retry */ 1420 to avoid an infinite loop on retry */
@@ -1639,7 +1639,7 @@ ack:
1639 if (queue_invalidate) 1639 if (queue_invalidate)
1640 ceph_queue_invalidate(inode); 1640 ceph_queue_invalidate(inode);
1641 1641
1642 if (session && drop_session_lock) 1642 if (session)
1643 mutex_unlock(&session->s_mutex); 1643 mutex_unlock(&session->s_mutex);
1644 if (took_snap_rwsem) 1644 if (took_snap_rwsem)
1645 up_read(&mdsc->snap_rwsem); 1645 up_read(&mdsc->snap_rwsem);
@@ -2688,14 +2688,17 @@ void ceph_handle_caps(struct ceph_mds_session *session,
2688 case CEPH_CAP_OP_REVOKE: 2688 case CEPH_CAP_OP_REVOKE:
2689 case CEPH_CAP_OP_GRANT: 2689 case CEPH_CAP_OP_GRANT:
2690 r = handle_cap_grant(inode, h, session, cap, msg->middle); 2690 r = handle_cap_grant(inode, h, session, cap, msg->middle);
2691 if (r == 1) 2691 if (r == 1) {
2692 ceph_check_caps(ceph_inode(inode), 2692 ceph_check_caps(ceph_inode(inode),
2693 CHECK_CAPS_NODELAY|CHECK_CAPS_AUTHONLY, 2693 CHECK_CAPS_NODELAY|CHECK_CAPS_AUTHONLY,
2694 session); 2694 session);
2695 else if (r == 2) 2695 session = NULL;
2696 } else if (r == 2) {
2696 ceph_check_caps(ceph_inode(inode), 2697 ceph_check_caps(ceph_inode(inode),
2697 CHECK_CAPS_NODELAY, 2698 CHECK_CAPS_NODELAY,
2698 session); 2699 session);
2700 session = NULL;
2701 }
2699 break; 2702 break;
2700 2703
2701 case CEPH_CAP_OP_FLUSH_ACK: 2704 case CEPH_CAP_OP_FLUSH_ACK:
@@ -2713,7 +2716,8 @@ void ceph_handle_caps(struct ceph_mds_session *session,
2713 } 2716 }
2714 2717
2715done: 2718done:
2716 mutex_unlock(&session->s_mutex); 2719 if (session)
2720 mutex_unlock(&session->s_mutex);
2717 2721
2718 if (check_caps) 2722 if (check_caps)
2719 ceph_check_caps(ceph_inode(inode), CHECK_CAPS_NODELAY, NULL); 2723 ceph_check_caps(ceph_inode(inode), CHECK_CAPS_NODELAY, NULL);