ceph: allow renewal of auth credentials

Add infrastructure to allow the mon_client to periodically renew its auth
credentials.  Also add a messenger callback that will force such a renewal
if a peer rejects our authenticator.

Signed-off-by: Yehuda Sadeh <yehuda@hq.newdream.net>
Signed-off-by: Sage Weil <sage@newdream.net>
diff --git a/fs/ceph/mon_client.c b/fs/ceph/mon_client.c
index 3f7ae7f..fec41a0 100644
--- a/fs/ceph/mon_client.c
+++ b/fs/ceph/mon_client.c
@@ -29,6 +29,8 @@
 
 const static struct ceph_connection_operations mon_con_ops;
 
+static int __validate_auth(struct ceph_mon_client *monc);
+
 /*
  * Decode a monmap blob (e.g., during mount).
  */
@@ -103,6 +105,7 @@
 		ceph_con_revoke(monc->con, monc->m_auth);
 		ceph_con_close(monc->con);
 		monc->cur_mon = -1;
+		monc->pending_auth = 0;
 		ceph_auth_reset(monc->auth);
 	}
 }
@@ -334,7 +337,7 @@
 
 out:
 	mutex_unlock(&monc->mutex);
-	wake_up(&client->mount_wq);
+	wake_up(&client->auth_wq);
 }
 
 /*
@@ -477,6 +480,11 @@
 		__open_session(monc);  /* continue hunting */
 	} else {
 		ceph_con_keepalive(monc->con);
+		mutex_unlock(&monc->mutex);
+
+		__validate_auth(monc);
+
+		mutex_lock(&monc->mutex);
 		if (monc->auth->ops->is_authenticated(monc->auth))
 			__send_subscribe(monc);
 	}
@@ -557,6 +565,7 @@
 		goto out_pool2;
 
 	monc->m_auth = ceph_msg_new(CEPH_MSG_AUTH, 4096, 0, 0, NULL);
+	monc->pending_auth = 0;
 	if (IS_ERR(monc->m_auth)) {
 		err = PTR_ERR(monc->m_auth);
 		monc->m_auth = NULL;
@@ -614,6 +623,15 @@
 	kfree(monc->monmap);
 }
 
+static void __send_prepared_auth_request(struct ceph_mon_client *monc, int len)
+{
+	monc->pending_auth = 1;
+	monc->m_auth->front.iov_len = len;
+	monc->m_auth->hdr.front_len = cpu_to_le32(len);
+	ceph_msg_get(monc->m_auth);  /* keep our ref */
+	ceph_con_send(monc->con, monc->m_auth);
+}
+
 
 static void handle_auth_reply(struct ceph_mon_client *monc,
 			      struct ceph_msg *msg)
@@ -621,18 +639,16 @@
 	int ret;
 
 	mutex_lock(&monc->mutex);
+	monc->pending_auth = 0;
 	ret = ceph_handle_auth_reply(monc->auth, msg->front.iov_base,
 				     msg->front.iov_len,
 				     monc->m_auth->front.iov_base,
 				     monc->m_auth->front_max);
 	if (ret < 0) {
-		monc->client->mount_err = ret;
-		wake_up(&monc->client->mount_wq);
+		monc->client->auth_err = ret;
+		wake_up(&monc->client->auth_wq);
 	} else if (ret > 0) {
-		monc->m_auth->front.iov_len = ret;
-		monc->m_auth->hdr.front_len = cpu_to_le32(ret);
-		ceph_msg_get(monc->m_auth);  /* keep our ref */
-		ceph_con_send(monc->con, monc->m_auth);
+		__send_prepared_auth_request(monc, ret);
 	} else if (monc->auth->ops->is_authenticated(monc->auth)) {
 		dout("authenticated, starting session\n");
 
@@ -645,6 +661,31 @@
 	mutex_unlock(&monc->mutex);
 }
 
+static int __validate_auth(struct ceph_mon_client *monc)
+{
+	int ret;
+
+	if (monc->pending_auth)
+		return 0;
+
+	ret = ceph_build_auth(monc->auth, monc->m_auth->front.iov_base,
+			      monc->m_auth->front_max);
+	if (ret <= 0)
+		return ret; /* either an error, or no need to authenticate */
+	__send_prepared_auth_request(monc, ret);
+	return 0;
+}
+
+int ceph_monc_validate_auth(struct ceph_mon_client *monc)
+{
+	int ret;
+
+	mutex_lock(&monc->mutex);
+	ret = __validate_auth(monc);
+	mutex_unlock(&monc->mutex);
+	return ret;
+}
+
 /*
  * handle incoming message
  */