eCryptfs: integrate eCryptfs device handle into the module.
[linux-2.6.git] / fs / ecryptfs / messaging.c
index 9cc2aec27b0dc5b8de698dd8779b0cb4e70682b8..c6038bd60897334158441586261758c5f5e195e8 100644 (file)
@@ -1,7 +1,7 @@
 /**
  * eCryptfs: Linux filesystem encryption layer
  *
- * Copyright (C) 2004-2006 International Business Machines Corp.
+ * Copyright (C) 2004-2008 International Business Machines Corp.
  *   Author(s): Michael A. Halcrow <mhalcrow@us.ibm.com>
  *             Tyler Hicks <tyhicks@ou.edu>
  *
@@ -26,13 +26,13 @@ static LIST_HEAD(ecryptfs_msg_ctx_free_list);
 static LIST_HEAD(ecryptfs_msg_ctx_alloc_list);
 static struct mutex ecryptfs_msg_ctx_lists_mux;
 
-static struct hlist_head *ecryptfs_daemon_id_hash;
-static struct mutex ecryptfs_daemon_id_hash_mux;
+static struct hlist_head *ecryptfs_daemon_hash;
+struct mutex ecryptfs_daemon_hash_mux;
 static int ecryptfs_hash_buckets;
 #define ecryptfs_uid_hash(uid) \
         hash_long((unsigned long)uid, ecryptfs_hash_buckets)
 
-static unsigned int ecryptfs_msg_counter;
+static u32 ecryptfs_msg_counter;
 static struct ecryptfs_msg_ctx *ecryptfs_msg_ctx_arr;
 
 /**
@@ -40,9 +40,10 @@ static struct ecryptfs_msg_ctx *ecryptfs_msg_ctx_arr;
  * @msg_ctx: The context that was acquired from the free list
  *
  * Acquires a context element from the free list and locks the mutex
- * on the context.  Returns zero on success; non-zero on error or upon
- * failure to acquire a free context element.  Be sure to lock the
- * list mutex before calling.
+ * on the context.  Sets the msg_ctx task to current.  Returns zero on
+ * success; non-zero on error or upon failure to acquire a free
+ * context element.  Must be called with ecryptfs_msg_ctx_lists_mux
+ * held.
  */
 static int ecryptfs_acquire_free_msg_ctx(struct ecryptfs_msg_ctx **msg_ctx)
 {
@@ -50,11 +51,11 @@ static int ecryptfs_acquire_free_msg_ctx(struct ecryptfs_msg_ctx **msg_ctx)
        int rc;
 
        if (list_empty(&ecryptfs_msg_ctx_free_list)) {
-               ecryptfs_printk(KERN_WARNING, "The eCryptfs free "
-                               "context list is empty.  It may be helpful to "
-                               "specify the ecryptfs_message_buf_len "
-                               "parameter to be greater than the current "
-                               "value of [%d]\n", ecryptfs_message_buf_len);
+               printk(KERN_WARNING "%s: The eCryptfs free "
+                      "context list is empty.  It may be helpful to "
+                      "specify the ecryptfs_message_buf_len "
+                      "parameter to be greater than the current "
+                      "value of [%d]\n", __func__, ecryptfs_message_buf_len);
                rc = -ENOMEM;
                goto out;
        }
@@ -75,8 +76,7 @@ out:
  * ecryptfs_msg_ctx_free_to_alloc
  * @msg_ctx: The context to move from the free list to the alloc list
  *
- * Be sure to lock the list mutex and the context mutex before
- * calling.
+ * Must be called with ecryptfs_msg_ctx_lists_mux held.
  */
 static void ecryptfs_msg_ctx_free_to_alloc(struct ecryptfs_msg_ctx *msg_ctx)
 {
@@ -89,36 +89,37 @@ static void ecryptfs_msg_ctx_free_to_alloc(struct ecryptfs_msg_ctx *msg_ctx)
  * ecryptfs_msg_ctx_alloc_to_free
  * @msg_ctx: The context to move from the alloc list to the free list
  *
- * Be sure to lock the list mutex and the context mutex before
- * calling.
+ * Must be called with ecryptfs_msg_ctx_lists_mux held.
  */
-static void ecryptfs_msg_ctx_alloc_to_free(struct ecryptfs_msg_ctx *msg_ctx)
+void ecryptfs_msg_ctx_alloc_to_free(struct ecryptfs_msg_ctx *msg_ctx)
 {
        list_move(&(msg_ctx->node), &ecryptfs_msg_ctx_free_list);
        if (msg_ctx->msg)
                kfree(msg_ctx->msg);
+       msg_ctx->msg = NULL;
        msg_ctx->state = ECRYPTFS_MSG_CTX_STATE_FREE;
 }
 
 /**
- * ecryptfs_find_daemon_id
- * @uid: The user id which maps to the desired daemon id
- * @id: If return value is zero, points to the desired daemon id
- *      pointer
+ * ecryptfs_find_daemon_by_euid
+ * @euid: The effective user id which maps to the desired daemon id
+ * @daemon: If return value is zero, points to the desired daemon pointer
  *
- * Search the hash list for the given user id.  Returns zero if the
- * user id exists in the list; non-zero otherwise.  The daemon id hash
- * mutex should be held before calling this function.
+ * Must be called with ecryptfs_daemon_hash_mux held.
+ *
+ * Search the hash list for the given user id.
+ *
+ * Returns zero if the user id exists in the list; non-zero otherwise.
  */
-static int ecryptfs_find_daemon_id(uid_t uid, struct ecryptfs_daemon_id **id)
+int ecryptfs_find_daemon_by_euid(struct ecryptfs_daemon **daemon, uid_t euid)
 {
        struct hlist_node *elem;
        int rc;
 
-       hlist_for_each_entry(*id, elem,
-                            &ecryptfs_daemon_id_hash[ecryptfs_uid_hash(uid)],
-                            id_chain) {
-               if ((*id)->uid == uid) {
+       hlist_for_each_entry(*daemon, elem,
+                            &ecryptfs_daemon_hash[ecryptfs_uid_hash(euid)],
+                            euid_chain) {
+               if ((*daemon)->euid == euid) {
                        rc = 0;
                        goto out;
                }
@@ -128,181 +129,291 @@ out:
        return rc;
 }
 
-static int ecryptfs_send_raw_message(unsigned int transport, u16 msg_type,
-                                    pid_t pid)
+static int
+ecryptfs_send_message_locked(unsigned int transport, char *data, int data_len,
+                            u8 msg_type, struct ecryptfs_msg_ctx **msg_ctx);
+
+/**
+ * ecryptfs_send_raw_message
+ * @transport: Transport type
+ * @msg_type: Message type
+ * @daemon: Daemon struct for recipient of message
+ *
+ * A raw message is one that does not include an ecryptfs_message
+ * struct. It simply has a type.
+ *
+ * Must be called with ecryptfs_daemon_hash_mux held.
+ *
+ * Returns zero on success; non-zero otherwise
+ */
+static int ecryptfs_send_raw_message(unsigned int transport, u8 msg_type,
+                                    struct ecryptfs_daemon *daemon)
 {
+       struct ecryptfs_msg_ctx *msg_ctx;
        int rc;
 
        switch(transport) {
        case ECRYPTFS_TRANSPORT_NETLINK:
-               rc = ecryptfs_send_netlink(NULL, 0, NULL, msg_type, 0, pid);
+               rc = ecryptfs_send_netlink(NULL, 0, NULL, msg_type, 0,
+                                          daemon->pid);
+               break;
+       case ECRYPTFS_TRANSPORT_MISCDEV:
+               rc = ecryptfs_send_message_locked(transport, NULL, 0, msg_type,
+                                                 &msg_ctx);
+               if (rc) {
+                       printk(KERN_ERR "%s: Error whilst attempting to send "
+                              "message via procfs; rc = [%d]\n", __func__, rc);
+                       goto out;
+               }
+               /* Raw messages are logically context-free (e.g., no
+                * reply is expected), so we set the state of the
+                * ecryptfs_msg_ctx object to indicate that it should
+                * be freed as soon as the transport sends out the message. */
+               mutex_lock(&msg_ctx->mux);
+               msg_ctx->state = ECRYPTFS_MSG_CTX_STATE_NO_REPLY;
+               mutex_unlock(&msg_ctx->mux);
                break;
        case ECRYPTFS_TRANSPORT_CONNECTOR:
        case ECRYPTFS_TRANSPORT_RELAYFS:
        default:
                rc = -ENOSYS;
        }
+out:
+       return rc;
+}
+
+/**
+ * ecryptfs_spawn_daemon - Create and initialize a new daemon struct
+ * @daemon: Pointer to set to newly allocated daemon struct
+ * @euid: Effective user id for the daemon
+ * @pid: Process id for the daemon
+ *
+ * Must be called ceremoniously while in possession of
+ * ecryptfs_sacred_daemon_hash_mux
+ *
+ * Returns zero on success; non-zero otherwise
+ */
+int
+ecryptfs_spawn_daemon(struct ecryptfs_daemon **daemon, uid_t euid, pid_t pid)
+{
+       int rc = 0;
+
+       (*daemon) = kzalloc(sizeof(**daemon), GFP_KERNEL);
+       if (!(*daemon)) {
+               rc = -ENOMEM;
+               printk(KERN_ERR "%s: Failed to allocate [%Zd] bytes of "
+                      "GFP_KERNEL memory\n", __func__, sizeof(**daemon));
+               goto out;
+       }
+       (*daemon)->euid = euid;
+       (*daemon)->pid = pid;
+       (*daemon)->task = current;
+       mutex_init(&(*daemon)->mux);
+       INIT_LIST_HEAD(&(*daemon)->msg_ctx_out_queue);
+       init_waitqueue_head(&(*daemon)->wait);
+       (*daemon)->num_queued_msg_ctx = 0;
+       hlist_add_head(&(*daemon)->euid_chain,
+                      &ecryptfs_daemon_hash[ecryptfs_uid_hash(euid)]);
+out:
        return rc;
 }
 
 /**
  * ecryptfs_process_helo
  * @transport: The underlying transport (netlink, etc.)
- * @uid: The user ID owner of the message
+ * @euid: The user ID owner of the message
  * @pid: The process ID for the userspace program that sent the
  *       message
  *
- * Adds the uid and pid values to the daemon id hash.  If a uid
+ * Adds the euid and pid values to the daemon euid hash.  If an euid
  * already has a daemon pid registered, the daemon will be
- * unregistered before the new daemon id is put into the hash list.
- * Returns zero after adding a new daemon id to the hash list;
+ * unregistered before the new daemon is put into the hash list.
+ * Returns zero after adding a new daemon to the hash list;
  * non-zero otherwise.
  */
-int ecryptfs_process_helo(unsigned int transport, uid_t uid, pid_t pid)
+int ecryptfs_process_helo(unsigned int transport, uid_t euid, pid_t pid)
 {
-       struct ecryptfs_daemon_id *new_id;
-       struct ecryptfs_daemon_id *old_id;
+       struct ecryptfs_daemon *new_daemon;
+       struct ecryptfs_daemon *old_daemon;
        int rc;
 
-       mutex_lock(&ecryptfs_daemon_id_hash_mux);
-       new_id = kmalloc(sizeof(*new_id), GFP_KERNEL);
-       if (!new_id) {
-               rc = -ENOMEM;
-               ecryptfs_printk(KERN_ERR, "Failed to allocate memory; unable "
-                               "to register daemon [%d] for user [%d]\n",
-                               pid, uid);
-               goto unlock;
-       }
-       if (!ecryptfs_find_daemon_id(uid, &old_id)) {
+       mutex_lock(&ecryptfs_daemon_hash_mux);
+       rc = ecryptfs_find_daemon_by_euid(&old_daemon, euid);
+       if (rc != 0) {
                printk(KERN_WARNING "Received request from user [%d] "
                       "to register daemon [%d]; unregistering daemon "
-                      "[%d]\n", uid, pid, old_id->pid);
-               hlist_del(&old_id->id_chain);
-               rc = ecryptfs_send_raw_message(transport, ECRYPTFS_NLMSG_QUIT,
-                                              old_id->pid);
+                      "[%d]\n", euid, pid, old_daemon->pid);
+               rc = ecryptfs_send_raw_message(transport, ECRYPTFS_MSG_QUIT,
+                                              old_daemon);
                if (rc)
                        printk(KERN_WARNING "Failed to send QUIT "
                               "message to daemon [%d]; rc = [%d]\n",
-                              old_id->pid, rc);
-               kfree(old_id);
+                              old_daemon->pid, rc);
+               hlist_del(&old_daemon->euid_chain);
+               kfree(old_daemon);
        }
-       new_id->uid = uid;
-       new_id->pid = pid;
-       hlist_add_head(&new_id->id_chain,
-                      &ecryptfs_daemon_id_hash[ecryptfs_uid_hash(uid)]);
-       rc = 0;
-unlock:
-       mutex_unlock(&ecryptfs_daemon_id_hash_mux);
+       rc = ecryptfs_spawn_daemon(&new_daemon, euid, pid);
+       if (rc)
+               printk(KERN_ERR "%s: The gods are displeased with this attempt "
+                      "to create a new daemon object for euid [%d]; pid [%d]; "
+                      "rc = [%d]\n", __func__, euid, pid, rc);
+       mutex_unlock(&ecryptfs_daemon_hash_mux);
+       return rc;
+}
+
+/**
+ * ecryptfs_exorcise_daemon - Destroy the daemon struct
+ *
+ * Must be called ceremoniously while in possession of
+ * ecryptfs_daemon_hash_mux and the daemon's own mux.
+ */
+int ecryptfs_exorcise_daemon(struct ecryptfs_daemon *daemon)
+{
+       struct ecryptfs_msg_ctx *msg_ctx, *msg_ctx_tmp;
+       int rc = 0;
+
+       mutex_lock(&daemon->mux);
+       if ((daemon->flags & ECRYPTFS_DAEMON_IN_READ)
+           || (daemon->flags & ECRYPTFS_DAEMON_IN_POLL)) {
+               rc = -EBUSY;
+               printk(KERN_WARNING "%s: Attempt to destroy daemon with pid "
+                      "[%d], but it is in the midst of a read or a poll\n",
+                      __func__, daemon->pid);
+               mutex_unlock(&daemon->mux);
+               goto out;
+       }
+       list_for_each_entry_safe(msg_ctx, msg_ctx_tmp,
+                                &daemon->msg_ctx_out_queue, daemon_out_list) {
+               list_del(&msg_ctx->daemon_out_list);
+               daemon->num_queued_msg_ctx--;
+               printk(KERN_WARNING "%s: Warning: dropping message that is in "
+                      "the out queue of a dying daemon\n", __func__);
+               ecryptfs_msg_ctx_alloc_to_free(msg_ctx);
+       }
+       hlist_del(&daemon->euid_chain);
+       if (daemon->task)
+               wake_up_process(daemon->task);
+       mutex_unlock(&daemon->mux);
+       memset(daemon, 0, sizeof(*daemon));
+       kfree(daemon);
+out:
        return rc;
 }
 
 /**
  * ecryptfs_process_quit
- * @uid: The user ID owner of the message
+ * @euid: The user ID owner of the message
  * @pid: The process ID for the userspace program that sent the
  *       message
  *
- * Deletes the corresponding daemon id for the given uid and pid, if
+ * Deletes the corresponding daemon for the given euid and pid, if
  * it is the registered that is requesting the deletion. Returns zero
- * after deleting the desired daemon id; non-zero otherwise.
+ * after deleting the desired daemon; non-zero otherwise.
  */
-int ecryptfs_process_quit(uid_t uid, pid_t pid)
+int ecryptfs_process_quit(uid_t euid, pid_t pid)
 {
-       struct ecryptfs_daemon_id *id;
+       struct ecryptfs_daemon *daemon;
        int rc;
 
-       mutex_lock(&ecryptfs_daemon_id_hash_mux);
-       if (ecryptfs_find_daemon_id(uid, &id)) {
-               rc = -EINVAL;
-               ecryptfs_printk(KERN_ERR, "Received request from user [%d] to "
-                               "unregister unrecognized daemon [%d]\n", uid,
-                               pid);
-               goto unlock;
-       }
-       if (id->pid != pid) {
+       mutex_lock(&ecryptfs_daemon_hash_mux);
+       rc = ecryptfs_find_daemon_by_euid(&daemon, euid);
+       if (rc || !daemon) {
                rc = -EINVAL;
-               ecryptfs_printk(KERN_WARNING, "Received request from user [%d] "
-                               "with pid [%d] to unregister daemon [%d]\n",
-                               uid, pid, id->pid);
-               goto unlock;
+               printk(KERN_ERR "Received request from user [%d] to "
+                      "unregister unrecognized daemon [%d]\n", euid, pid);
+               goto out_unlock;
        }
-       hlist_del(&id->id_chain);
-       kfree(id);
-       rc = 0;
-unlock:
-       mutex_unlock(&ecryptfs_daemon_id_hash_mux);
+       rc = ecryptfs_exorcise_daemon(daemon);
+out_unlock:
+       mutex_unlock(&ecryptfs_daemon_hash_mux);
        return rc;
 }
 
 /**
  * ecryptfs_process_reponse
  * @msg: The ecryptfs message received; the caller should sanity check
- *       msg->data_len
+ *       msg->data_len and free the memory
  * @pid: The process ID of the userspace application that sent the
  *       message
- * @seq: The sequence number of the message
+ * @seq: The sequence number of the message; must match the sequence
+ *       number for the existing message context waiting for this
+ *       response
+ *
+ * Processes a response message after sending an operation request to
+ * userspace. Some other process is awaiting this response. Before
+ * sending out its first communications, the other process allocated a
+ * msg_ctx from the ecryptfs_msg_ctx_arr at a particular index. The
+ * response message contains this index so that we can copy over the
+ * response message into the msg_ctx that the process holds a
+ * reference to. The other process is going to wake up, check to see
+ * that msg_ctx->state == ECRYPTFS_MSG_CTX_STATE_DONE, and then
+ * proceed to read off and process the response message. Returns zero
+ * upon delivery to desired context element; non-zero upon delivery
+ * failure or error.
  *
- * Processes a response message after sending a operation request to
- * userspace. Returns zero upon delivery to desired context element;
- * non-zero upon delivery failure or error.
+ * Returns zero on success; non-zero otherwise
  */
-int ecryptfs_process_response(struct ecryptfs_message *msg, uid_t uid,
+int ecryptfs_process_response(struct ecryptfs_message *msg, uid_t euid,
                              pid_t pid, u32 seq)
 {
-       struct ecryptfs_daemon_id *id;
+       struct ecryptfs_daemon *daemon;
        struct ecryptfs_msg_ctx *msg_ctx;
-       int msg_size;
+       size_t msg_size;
        int rc;
 
        if (msg->index >= ecryptfs_message_buf_len) {
                rc = -EINVAL;
-               ecryptfs_printk(KERN_ERR, "Attempt to reference "
-                               "context buffer at index [%d]; maximum "
-                               "allowable is [%d]\n", msg->index,
-                               (ecryptfs_message_buf_len - 1));
+               printk(KERN_ERR "%s: Attempt to reference "
+                      "context buffer at index [%d]; maximum "
+                      "allowable is [%d]\n", __func__, msg->index,
+                      (ecryptfs_message_buf_len - 1));
                goto out;
        }
        msg_ctx = &ecryptfs_msg_ctx_arr[msg->index];
        mutex_lock(&msg_ctx->mux);
-       if (ecryptfs_find_daemon_id(msg_ctx->task->euid, &id)) {
+       mutex_lock(&ecryptfs_daemon_hash_mux);
+       rc = ecryptfs_find_daemon_by_euid(&daemon, msg_ctx->task->euid);
+       mutex_unlock(&ecryptfs_daemon_hash_mux);
+       if (rc) {
                rc = -EBADMSG;
-               ecryptfs_printk(KERN_WARNING, "User [%d] received a "
-                               "message response from process [%d] but does "
-                               "not have a registered daemon\n",
-                               msg_ctx->task->euid, pid);
+               printk(KERN_WARNING "%s: User [%d] received a "
+                      "message response from process [%d] but does "
+                      "not have a registered daemon\n", __func__,
+                      msg_ctx->task->euid, pid);
                goto wake_up;
        }
-       if (msg_ctx->task->euid != uid) {
+       if (msg_ctx->task->euid != euid) {
                rc = -EBADMSG;
-               ecryptfs_printk(KERN_WARNING, "Received message from user "
-                               "[%d]; expected message from user [%d]\n",
-                               uid, msg_ctx->task->euid);
+               printk(KERN_WARNING "%s: Received message from user "
+                      "[%d]; expected message from user [%d]\n", __func__,
+                      euid, msg_ctx->task->euid);
                goto unlock;
        }
-       if (id->pid != pid) {
+       if (daemon->pid != pid) {
                rc = -EBADMSG;
-               ecryptfs_printk(KERN_ERR, "User [%d] received a "
-                               "message response from an unrecognized "
-                               "process [%d]\n", msg_ctx->task->euid, pid);
+               printk(KERN_ERR "%s: User [%d] sent a message response "
+                      "from an unrecognized process [%d]\n",
+                      __func__, msg_ctx->task->euid, pid);
                goto unlock;
        }
        if (msg_ctx->state != ECRYPTFS_MSG_CTX_STATE_PENDING) {
                rc = -EINVAL;
-               ecryptfs_printk(KERN_WARNING, "Desired context element is not "
-                               "pending a response\n");
+               printk(KERN_WARNING "%s: Desired context element is not "
+                      "pending a response\n", __func__);
                goto unlock;
        } else if (msg_ctx->counter != seq) {
                rc = -EINVAL;
-               ecryptfs_printk(KERN_WARNING, "Invalid message sequence; "
-                               "expected [%d]; received [%d]\n",
-                               msg_ctx->counter, seq);
+               printk(KERN_WARNING "%s: Invalid message sequence; "
+                      "expected [%d]; received [%d]\n", __func__,
+                      msg_ctx->counter, seq);
                goto unlock;
        }
-       msg_size = sizeof(*msg) + msg->data_len;
+       msg_size = (sizeof(*msg) + msg->data_len);
        msg_ctx->msg = kmalloc(msg_size, GFP_KERNEL);
        if (!msg_ctx->msg) {
                rc = -ENOMEM;
-               ecryptfs_printk(KERN_ERR, "Failed to allocate memory\n");
+               printk(KERN_ERR "%s: Failed to allocate [%Zd] bytes of "
+                      "GFP_KERNEL memory\n", __func__, msg_size);
                goto unlock;
        }
        memcpy(msg_ctx->msg, msg, msg_size);
@@ -317,34 +428,37 @@ out:
 }
 
 /**
- * ecryptfs_send_message
+ * ecryptfs_send_message_locked
  * @transport: The transport over which to send the message (i.e.,
  *             netlink)
  * @data: The data to send
  * @data_len: The length of data
  * @msg_ctx: The message context allocated for the send
+ *
+ * Must be called with ecryptfs_daemon_hash_mux held.
+ *
+ * Returns zero on success; non-zero otherwise
  */
-int ecryptfs_send_message(unsigned int transport, char *data, int data_len,
-                         struct ecryptfs_msg_ctx **msg_ctx)
+static int
+ecryptfs_send_message_locked(unsigned int transport, char *data, int data_len,
+                            u8 msg_type, struct ecryptfs_msg_ctx **msg_ctx)
 {
-       struct ecryptfs_daemon_id *id;
+       struct ecryptfs_daemon *daemon;
        int rc;
 
-       mutex_lock(&ecryptfs_daemon_id_hash_mux);
-       if (ecryptfs_find_daemon_id(current->euid, &id)) {
-               mutex_unlock(&ecryptfs_daemon_id_hash_mux);
+       rc = ecryptfs_find_daemon_by_euid(&daemon, current->euid);
+       if (rc || !daemon) {
                rc = -ENOTCONN;
-               ecryptfs_printk(KERN_ERR, "User [%d] does not have a daemon "
-                               "registered\n", current->euid);
+               printk(KERN_ERR "%s: User [%d] does not have a daemon "
+                      "registered\n", __func__, current->euid);
                goto out;
        }
-       mutex_unlock(&ecryptfs_daemon_id_hash_mux);
        mutex_lock(&ecryptfs_msg_ctx_lists_mux);
        rc = ecryptfs_acquire_free_msg_ctx(msg_ctx);
        if (rc) {
                mutex_unlock(&ecryptfs_msg_ctx_lists_mux);
-               ecryptfs_printk(KERN_WARNING, "Could not claim a free "
-                               "context element\n");
+               printk(KERN_WARNING "%s: Could not claim a free "
+                      "context element\n", __func__);
                goto out;
        }
        ecryptfs_msg_ctx_free_to_alloc(*msg_ctx);
@@ -352,22 +466,49 @@ int ecryptfs_send_message(unsigned int transport, char *data, int data_len,
        mutex_unlock(&ecryptfs_msg_ctx_lists_mux);
        switch (transport) {
        case ECRYPTFS_TRANSPORT_NETLINK:
-               rc = ecryptfs_send_netlink(data, data_len, *msg_ctx,
-                                          ECRYPTFS_NLMSG_REQUEST, 0, id->pid);
+               rc = ecryptfs_send_netlink(data, data_len, *msg_ctx, msg_type,
+                                          0, daemon->pid);
+               break;
+       case ECRYPTFS_TRANSPORT_MISCDEV:
+               rc = ecryptfs_send_miscdev(data, data_len, *msg_ctx, msg_type,
+                                          0, daemon);
                break;
        case ECRYPTFS_TRANSPORT_CONNECTOR:
        case ECRYPTFS_TRANSPORT_RELAYFS:
        default:
                rc = -ENOSYS;
        }
-       if (rc) {
-               printk(KERN_ERR "Error attempting to send message to userspace "
-                      "daemon; rc = [%d]\n", rc);
-       }
+       if (rc)
+               printk(KERN_ERR "%s: Error attempting to send message to "
+                      "userspace daemon; rc = [%d]\n", __func__, rc);
 out:
        return rc;
 }
 
+/**
+ * ecryptfs_send_message
+ * @transport: The transport over which to send the message (i.e.,
+ *             netlink)
+ * @data: The data to send
+ * @data_len: The length of data
+ * @msg_ctx: The message context allocated for the send
+ *
+ * Grabs ecryptfs_daemon_hash_mux.
+ *
+ * Returns zero on success; non-zero otherwise
+ */
+int ecryptfs_send_message(unsigned int transport, char *data, int data_len,
+                         struct ecryptfs_msg_ctx **msg_ctx)
+{
+       int rc;
+
+       mutex_lock(&ecryptfs_daemon_hash_mux);
+       rc = ecryptfs_send_message_locked(transport, data, data_len,
+                                         ECRYPTFS_MSG_REQUEST, msg_ctx);
+       mutex_unlock(&ecryptfs_daemon_hash_mux);
+       return rc;
+}
+
 /**
  * ecryptfs_wait_for_response
  * @msg_ctx: The context that was assigned when sending a message
@@ -377,7 +518,7 @@ out:
  * of time exceeds ecryptfs_message_wait_timeout.  If zero is
  * returned, msg will point to a valid message from userspace; a
  * non-zero value is returned upon failure to receive a message or an
- * error occurs.
+ * error occurs. Callee must free @msg on success.
  */
 int ecryptfs_wait_for_response(struct ecryptfs_msg_ctx *msg_ctx,
                               struct ecryptfs_message **msg)
@@ -413,32 +554,32 @@ int ecryptfs_init_messaging(unsigned int transport)
 
        if (ecryptfs_number_of_users > ECRYPTFS_MAX_NUM_USERS) {
                ecryptfs_number_of_users = ECRYPTFS_MAX_NUM_USERS;
-               ecryptfs_printk(KERN_WARNING, "Specified number of users is "
-                               "too large, defaulting to [%d] users\n",
-                               ecryptfs_number_of_users);
+               printk(KERN_WARNING "%s: Specified number of users is "
+                      "too large, defaulting to [%d] users\n", __func__,
+                      ecryptfs_number_of_users);
        }
-       mutex_init(&ecryptfs_daemon_id_hash_mux);
-       mutex_lock(&ecryptfs_daemon_id_hash_mux);
+       mutex_init(&ecryptfs_daemon_hash_mux);
+       mutex_lock(&ecryptfs_daemon_hash_mux);
        ecryptfs_hash_buckets = 1;
        while (ecryptfs_number_of_users >> ecryptfs_hash_buckets)
                ecryptfs_hash_buckets++;
-       ecryptfs_daemon_id_hash = kmalloc(sizeof(struct hlist_head)
-                                         * ecryptfs_hash_buckets, GFP_KERNEL);
-       if (!ecryptfs_daemon_id_hash) {
+       ecryptfs_daemon_hash = kmalloc((sizeof(struct hlist_head)
+                                       * ecryptfs_hash_buckets), GFP_KERNEL);
+       if (!ecryptfs_daemon_hash) {
                rc = -ENOMEM;
-               ecryptfs_printk(KERN_ERR, "Failed to allocate memory\n");
-               mutex_unlock(&ecryptfs_daemon_id_hash_mux);
+               printk(KERN_ERR "%s: Failed to allocate memory\n", __func__);
+               mutex_unlock(&ecryptfs_daemon_hash_mux);
                goto out;
        }
        for (i = 0; i < ecryptfs_hash_buckets; i++)
-               INIT_HLIST_HEAD(&ecryptfs_daemon_id_hash[i]);
-       mutex_unlock(&ecryptfs_daemon_id_hash_mux);
-
+               INIT_HLIST_HEAD(&ecryptfs_daemon_hash[i]);
+       mutex_unlock(&ecryptfs_daemon_hash_mux);
        ecryptfs_msg_ctx_arr = kmalloc((sizeof(struct ecryptfs_msg_ctx)
-                                     * ecryptfs_message_buf_len), GFP_KERNEL);
+                                       * ecryptfs_message_buf_len),
+                                      GFP_KERNEL);
        if (!ecryptfs_msg_ctx_arr) {
                rc = -ENOMEM;
-               ecryptfs_printk(KERN_ERR, "Failed to allocate memory\n");
+               printk(KERN_ERR "%s: Failed to allocate memory\n", __func__);
                goto out;
        }
        mutex_init(&ecryptfs_msg_ctx_lists_mux);
@@ -446,6 +587,7 @@ int ecryptfs_init_messaging(unsigned int transport)
        ecryptfs_msg_counter = 0;
        for (i = 0; i < ecryptfs_message_buf_len; i++) {
                INIT_LIST_HEAD(&ecryptfs_msg_ctx_arr[i].node);
+               INIT_LIST_HEAD(&ecryptfs_msg_ctx_arr[i].daemon_out_list);
                mutex_init(&ecryptfs_msg_ctx_arr[i].mux);
                mutex_lock(&ecryptfs_msg_ctx_arr[i].mux);
                ecryptfs_msg_ctx_arr[i].index = i;
@@ -464,6 +606,11 @@ int ecryptfs_init_messaging(unsigned int transport)
                if (rc)
                        ecryptfs_release_messaging(transport);
                break;
+       case ECRYPTFS_TRANSPORT_MISCDEV:
+               rc = ecryptfs_init_ecryptfs_miscdev();
+               if (rc)
+                       ecryptfs_release_messaging(transport);
+               break;
        case ECRYPTFS_TRANSPORT_CONNECTOR:
        case ECRYPTFS_TRANSPORT_RELAYFS:
        default:
@@ -488,27 +635,37 @@ void ecryptfs_release_messaging(unsigned int transport)
                kfree(ecryptfs_msg_ctx_arr);
                mutex_unlock(&ecryptfs_msg_ctx_lists_mux);
        }
-       if (ecryptfs_daemon_id_hash) {
+       if (ecryptfs_daemon_hash) {
                struct hlist_node *elem;
-               struct ecryptfs_daemon_id *id;
+               struct ecryptfs_daemon *daemon;
                int i;
 
-               mutex_lock(&ecryptfs_daemon_id_hash_mux);
+               mutex_lock(&ecryptfs_daemon_hash_mux);
                for (i = 0; i < ecryptfs_hash_buckets; i++) {
-                       hlist_for_each_entry(id, elem,
-                                            &ecryptfs_daemon_id_hash[i],
-                                            id_chain) {
-                               hlist_del(elem);
-                               kfree(id);
+                       int rc;
+
+                       hlist_for_each_entry(daemon, elem,
+                                            &ecryptfs_daemon_hash[i],
+                                            euid_chain) {
+                               rc = ecryptfs_exorcise_daemon(daemon);
+                               if (rc)
+                                       printk(KERN_ERR "%s: Error whilst "
+                                              "attempting to destroy daemon; "
+                                              "rc = [%d]. Dazed and confused, "
+                                              "but trying to continue.\n",
+                                              __func__, rc);
                        }
                }
-               kfree(ecryptfs_daemon_id_hash);
-               mutex_unlock(&ecryptfs_daemon_id_hash_mux);
+               kfree(ecryptfs_daemon_hash);
+               mutex_unlock(&ecryptfs_daemon_hash_mux);
        }
        switch(transport) {
        case ECRYPTFS_TRANSPORT_NETLINK:
                ecryptfs_release_netlink();
                break;
+       case ECRYPTFS_TRANSPORT_MISCDEV:
+               ecryptfs_destroy_ecryptfs_miscdev();
+               break;
        case ECRYPTFS_TRANSPORT_CONNECTOR:
        case ECRYPTFS_TRANSPORT_RELAYFS:
        default: