aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Halcrow <mhalcrow@us.ibm.com>2008-04-29 03:59:50 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-04-29 11:06:07 -0400
commit8bf2debd5f7bf12d122124e34fec14af5b1e8ecf (patch)
treefaa6ff4ad5a9ec3725279a6408ee783a9e65f35d
parent9c3580aa52195699065bc2d7242b1c7e3e6903fa (diff)
eCryptfs: introduce device handle for userspace daemon communications
A regular device file was my real preference from the get-go, but I went with netlink at the time because I thought it would be less complex for managing send queues (i.e., just do a unicast and move on). It turns out that we do not really get that much complexity reduction with netlink, and netlink is more heavyweight than a device handle. In addition, the netlink interface to eCryptfs has been broken since 2.6.24. I am assuming this is a bug in how eCryptfs uses netlink, since the other in-kernel users of netlink do not seem to be having any problems. I have had one report of a user successfully using eCryptfs with netlink on 2.6.24, but for my own systems, when starting the userspace daemon, the initial helo message sent to the eCryptfs kernel module results in an oops right off the bat. I spent some time looking at it, but I have not yet found the cause. The netlink interface breaking gave me the motivation to just finish my patch to migrate to a regular device handle. If I cannot find out soon why the netlink interface in eCryptfs broke, I am likely to just send a patch to disable it in 2.6.24 and 2.6.25. I would like the device handle to be the preferred means of communicating with the userspace daemon from 2.6.26 on forward. This patch: Functions to facilitate reading and writing to the eCryptfs miscellaneous device handle. This will replace the netlink interface as the preferred mechanism for communicating with the userspace eCryptfs daemon. Each user has his own daemon, which registers itself by opening the eCryptfs device handle. Only one daemon per euid may be registered at any given time. The eCryptfs module sends a message to a daemon by adding its message to the daemon's outgoing message queue. The daemon reads the device handle to get the oldest message off the queue. Incoming messages from the userspace daemon are immediately handled. If the message is a response, then the corresponding process that is blocked waiting for the response is awakened. Signed-off-by: Michael Halcrow <mhalcrow@us.ibm.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--fs/ecryptfs/miscdev.c580
1 files changed, 580 insertions, 0 deletions
diff --git a/fs/ecryptfs/miscdev.c b/fs/ecryptfs/miscdev.c
new file mode 100644
index 000000000000..72dfec48ea22
--- /dev/null
+++ b/fs/ecryptfs/miscdev.c
@@ -0,0 +1,580 @@
1/**
2 * eCryptfs: Linux filesystem encryption layer
3 *
4 * Copyright (C) 2008 International Business Machines Corp.
5 * Author(s): Michael A. Halcrow <mhalcrow@us.ibm.com>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License version
9 * 2 as published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 * 02111-1307, USA.
20 */
21
22#include <linux/fs.h>
23#include <linux/hash.h>
24#include <linux/random.h>
25#include <linux/miscdevice.h>
26#include <linux/poll.h>
27#include <linux/wait.h>
28#include <linux/module.h>
29#include "ecryptfs_kernel.h"
30
31static atomic_t ecryptfs_num_miscdev_opens;
32
33/**
34 * ecryptfs_miscdev_poll
35 * @file: dev file (ignored)
36 * @pt: dev poll table (ignored)
37 *
38 * Returns the poll mask
39 */
40static unsigned int
41ecryptfs_miscdev_poll(struct file *file, poll_table *pt)
42{
43 struct ecryptfs_daemon *daemon;
44 unsigned int mask = 0;
45 int rc;
46
47 mutex_lock(&ecryptfs_daemon_hash_mux);
48 /* TODO: Just use file->private_data? */
49 rc = ecryptfs_find_daemon_by_euid(&daemon, current->euid);
50 BUG_ON(rc || !daemon);
51 mutex_lock(&daemon->mux);
52 mutex_unlock(&ecryptfs_daemon_hash_mux);
53 if (daemon->flags & ECRYPTFS_DAEMON_ZOMBIE) {
54 printk(KERN_WARNING "%s: Attempt to poll on zombified "
55 "daemon\n", __func__);
56 goto out_unlock_daemon;
57 }
58 if (daemon->flags & ECRYPTFS_DAEMON_IN_READ)
59 goto out_unlock_daemon;
60 if (daemon->flags & ECRYPTFS_DAEMON_IN_POLL)
61 goto out_unlock_daemon;
62 daemon->flags |= ECRYPTFS_DAEMON_IN_POLL;
63 mutex_unlock(&daemon->mux);
64 poll_wait(file, &daemon->wait, pt);
65 mutex_lock(&daemon->mux);
66 if (!list_empty(&daemon->msg_ctx_out_queue))
67 mask |= POLLIN | POLLRDNORM;
68out_unlock_daemon:
69 daemon->flags &= ~ECRYPTFS_DAEMON_IN_POLL;
70 mutex_unlock(&daemon->mux);
71 return mask;
72}
73
74/**
75 * ecryptfs_miscdev_open
76 * @inode: inode of miscdev handle (ignored)
77 * @file: file for miscdev handle (ignored)
78 *
79 * Returns zero on success; non-zero otherwise
80 */
81static int
82ecryptfs_miscdev_open(struct inode *inode, struct file *file)
83{
84 struct ecryptfs_daemon *daemon = NULL;
85 int rc;
86
87 mutex_lock(&ecryptfs_daemon_hash_mux);
88 rc = try_module_get(THIS_MODULE);
89 if (rc == 0) {
90 rc = -EIO;
91 printk(KERN_ERR "%s: Error attempting to increment module use "
92 "count; rc = [%d]\n", __func__, rc);
93 goto out_unlock_daemon_list;
94 }
95 rc = ecryptfs_find_daemon_by_euid(&daemon, current->euid);
96 if (rc || !daemon) {
97 rc = ecryptfs_spawn_daemon(&daemon, current->euid,
98 current->pid);
99 if (rc) {
100 printk(KERN_ERR "%s: Error attempting to spawn daemon; "
101 "rc = [%d]\n", __func__, rc);
102 goto out_module_put_unlock_daemon_list;
103 }
104 }
105 mutex_lock(&daemon->mux);
106 if (daemon->pid != current->pid) {
107 rc = -EINVAL;
108 printk(KERN_ERR "%s: pid [%d] has registered with euid [%d], "
109 "but pid [%d] has attempted to open the handle "
110 "instead\n", __func__, daemon->pid, daemon->euid,
111 current->pid);
112 goto out_unlock_daemon;
113 }
114 if (daemon->flags & ECRYPTFS_DAEMON_MISCDEV_OPEN) {
115 rc = -EBUSY;
116 printk(KERN_ERR "%s: Miscellaneous device handle may only be "
117 "opened once per daemon; pid [%d] already has this "
118 "handle open\n", __func__, daemon->pid);
119 goto out_unlock_daemon;
120 }
121 daemon->flags |= ECRYPTFS_DAEMON_MISCDEV_OPEN;
122 atomic_inc(&ecryptfs_num_miscdev_opens);
123out_unlock_daemon:
124 mutex_unlock(&daemon->mux);
125out_module_put_unlock_daemon_list:
126 if (rc)
127 module_put(THIS_MODULE);
128out_unlock_daemon_list:
129 mutex_unlock(&ecryptfs_daemon_hash_mux);
130 return rc;
131}
132
133/**
134 * ecryptfs_miscdev_release
135 * @inode: inode of fs/ecryptfs/euid handle (ignored)
136 * @file: file for fs/ecryptfs/euid handle (ignored)
137 *
138 * This keeps the daemon registered until the daemon sends another
139 * ioctl to fs/ecryptfs/ctl or until the kernel module unregisters.
140 *
141 * Returns zero on success; non-zero otherwise
142 */
143static int
144ecryptfs_miscdev_release(struct inode *inode, struct file *file)
145{
146 struct ecryptfs_daemon *daemon = NULL;
147 int rc;
148
149 mutex_lock(&ecryptfs_daemon_hash_mux);
150 rc = ecryptfs_find_daemon_by_euid(&daemon, current->euid);
151 BUG_ON(rc || !daemon);
152 mutex_lock(&daemon->mux);
153 BUG_ON(daemon->pid != current->pid);
154 BUG_ON(!(daemon->flags & ECRYPTFS_DAEMON_MISCDEV_OPEN));
155 daemon->flags &= ~ECRYPTFS_DAEMON_MISCDEV_OPEN;
156 atomic_dec(&ecryptfs_num_miscdev_opens);
157 mutex_unlock(&daemon->mux);
158 rc = ecryptfs_exorcise_daemon(daemon);
159 if (rc) {
160 printk(KERN_CRIT "%s: Fatal error whilst attempting to "
161 "shut down daemon; rc = [%d]. Please report this "
162 "bug.\n", __func__, rc);
163 BUG();
164 }
165 module_put(THIS_MODULE);
166 mutex_unlock(&ecryptfs_daemon_hash_mux);
167 return rc;
168}
169
170/**
171 * ecryptfs_send_miscdev
172 * @data: Data to send to daemon; may be NULL
173 * @data_size: Amount of data to send to daemon
174 * @msg_ctx: Message context, which is used to handle the reply. If
175 * this is NULL, then we do not expect a reply.
176 * @msg_type: Type of message
177 * @msg_flags: Flags for message
178 * @daemon: eCryptfs daemon object
179 *
180 * Add msg_ctx to queue and then, if it exists, notify the blocked
181 * miscdevess about the data being available. Must be called with
182 * ecryptfs_daemon_hash_mux held.
183 *
184 * Returns zero on success; non-zero otherwise
185 */
186int ecryptfs_send_miscdev(char *data, size_t data_size,
187 struct ecryptfs_msg_ctx *msg_ctx, u8 msg_type,
188 u16 msg_flags, struct ecryptfs_daemon *daemon)
189{
190 int rc = 0;
191
192 mutex_lock(&msg_ctx->mux);
193 if (data) {
194 msg_ctx->msg = kmalloc((sizeof(*msg_ctx->msg) + data_size),
195 GFP_KERNEL);
196 if (!msg_ctx->msg) {
197 rc = -ENOMEM;
198 printk(KERN_ERR "%s: Out of memory whilst attempting "
199 "to kmalloc(%d, GFP_KERNEL)\n", __func__,
200 (sizeof(*msg_ctx->msg) + data_size));
201 goto out_unlock;
202 }
203 } else
204 msg_ctx->msg = NULL;
205 msg_ctx->msg->index = msg_ctx->index;
206 msg_ctx->msg->data_len = data_size;
207 msg_ctx->type = msg_type;
208 if (data) {
209 memcpy(msg_ctx->msg->data, data, data_size);
210 msg_ctx->msg_size = (sizeof(*msg_ctx->msg) + data_size);
211 } else
212 msg_ctx->msg_size = 0;
213 mutex_lock(&daemon->mux);
214 list_add_tail(&msg_ctx->daemon_out_list, &daemon->msg_ctx_out_queue);
215 daemon->num_queued_msg_ctx++;
216 wake_up_interruptible(&daemon->wait);
217 mutex_unlock(&daemon->mux);
218out_unlock:
219 mutex_unlock(&msg_ctx->mux);
220 return rc;
221}
222
223/**
224 * ecryptfs_miscdev_read - format and send message from queue
225 * @file: fs/ecryptfs/euid miscdevfs handle (ignored)
226 * @buf: User buffer into which to copy the next message on the daemon queue
227 * @count: Amount of space available in @buf
228 * @ppos: Offset in file (ignored)
229 *
230 * Pulls the most recent message from the daemon queue, formats it for
231 * being sent via a miscdevfs handle, and copies it into @buf
232 *
233 * Returns the number of bytes copied into the user buffer
234 */
235static int
236ecryptfs_miscdev_read(struct file *file, char __user *buf, size_t count,
237 loff_t *ppos)
238{
239 struct ecryptfs_daemon *daemon;
240 struct ecryptfs_msg_ctx *msg_ctx;
241 size_t packet_length_size;
242 u32 counter_nbo;
243 char packet_length[3];
244 size_t i;
245 size_t total_length;
246 int rc;
247
248 mutex_lock(&ecryptfs_daemon_hash_mux);
249 /* TODO: Just use file->private_data? */
250 rc = ecryptfs_find_daemon_by_euid(&daemon, current->euid);
251 BUG_ON(rc || !daemon);
252 mutex_lock(&daemon->mux);
253 if (daemon->flags & ECRYPTFS_DAEMON_ZOMBIE) {
254 rc = 0;
255 printk(KERN_WARNING "%s: Attempt to read from zombified "
256 "daemon\n", __func__);
257 goto out_unlock_daemon;
258 }
259 if (daemon->flags & ECRYPTFS_DAEMON_IN_READ) {
260 rc = 0;
261 goto out_unlock_daemon;
262 }
263 /* This daemon will not go away so long as this flag is set */
264 daemon->flags |= ECRYPTFS_DAEMON_IN_READ;
265 mutex_unlock(&ecryptfs_daemon_hash_mux);
266check_list:
267 if (list_empty(&daemon->msg_ctx_out_queue)) {
268 mutex_unlock(&daemon->mux);
269 rc = wait_event_interruptible(
270 daemon->wait, !list_empty(&daemon->msg_ctx_out_queue));
271 mutex_lock(&daemon->mux);
272 if (rc < 0) {
273 rc = 0;
274 goto out_unlock_daemon;
275 }
276 }
277 if (daemon->flags & ECRYPTFS_DAEMON_ZOMBIE) {
278 rc = 0;
279 goto out_unlock_daemon;
280 }
281 if (list_empty(&daemon->msg_ctx_out_queue)) {
282 /* Something else jumped in since the
283 * wait_event_interruptable() and removed the
284 * message from the queue; try again */
285 goto check_list;
286 }
287 BUG_ON(current->euid != daemon->euid);
288 BUG_ON(current->pid != daemon->pid);
289 msg_ctx = list_first_entry(&daemon->msg_ctx_out_queue,
290 struct ecryptfs_msg_ctx, daemon_out_list);
291 BUG_ON(!msg_ctx);
292 mutex_lock(&msg_ctx->mux);
293 if (msg_ctx->msg) {
294 rc = ecryptfs_write_packet_length(packet_length,
295 msg_ctx->msg_size,
296 &packet_length_size);
297 if (rc) {
298 rc = 0;
299 printk(KERN_WARNING "%s: Error writing packet length; "
300 "rc = [%d]\n", __func__, rc);
301 goto out_unlock_msg_ctx;
302 }
303 } else {
304 packet_length_size = 0;
305 msg_ctx->msg_size = 0;
306 }
307 /* miscdevfs packet format:
308 * Octet 0: Type
309 * Octets 1-4: network byte order msg_ctx->counter
310 * Octets 5-N0: Size of struct ecryptfs_message to follow
311 * Octets N0-N1: struct ecryptfs_message (including data)
312 *
313 * Octets 5-N1 not written if the packet type does not
314 * include a message */
315 total_length = (1 + 4 + packet_length_size + msg_ctx->msg_size);
316 if (count < total_length) {
317 rc = 0;
318 printk(KERN_WARNING "%s: Only given user buffer of "
319 "size [%Zd], but we need [%Zd] to read the "
320 "pending message\n", __func__, count, total_length);
321 goto out_unlock_msg_ctx;
322 }
323 i = 0;
324 buf[i++] = msg_ctx->type;
325 counter_nbo = cpu_to_be32(msg_ctx->counter);
326 memcpy(&buf[i], (char *)&counter_nbo, 4);
327 i += 4;
328 if (msg_ctx->msg) {
329 memcpy(&buf[i], packet_length, packet_length_size);
330 i += packet_length_size;
331 rc = copy_to_user(&buf[i], msg_ctx->msg, msg_ctx->msg_size);
332 if (rc) {
333 printk(KERN_ERR "%s: copy_to_user returned error "
334 "[%d]\n", __func__, rc);
335 goto out_unlock_msg_ctx;
336 }
337 i += msg_ctx->msg_size;
338 }
339 rc = i;
340 list_del(&msg_ctx->daemon_out_list);
341 kfree(msg_ctx->msg);
342 msg_ctx->msg = NULL;
343 /* We do not expect a reply from the userspace daemon for any
344 * message type other than ECRYPTFS_MSG_REQUEST */
345 if (msg_ctx->type != ECRYPTFS_MSG_REQUEST)
346 ecryptfs_msg_ctx_alloc_to_free(msg_ctx);
347out_unlock_msg_ctx:
348 mutex_unlock(&msg_ctx->mux);
349out_unlock_daemon:
350 daemon->flags &= ~ECRYPTFS_DAEMON_IN_READ;
351 mutex_unlock(&daemon->mux);
352 return rc;
353}
354
355/**
356 * ecryptfs_miscdev_helo
357 * @euid: effective user id of miscdevess sending helo packet
358 * @pid: miscdevess id of miscdevess sending helo packet
359 *
360 * Returns zero on success; non-zero otherwise
361 */
362static int ecryptfs_miscdev_helo(uid_t uid, pid_t pid)
363{
364 int rc;
365
366 rc = ecryptfs_process_helo(ECRYPTFS_TRANSPORT_MISCDEV, uid, pid);
367 if (rc)
368 printk(KERN_WARNING "Error processing HELO; rc = [%d]\n", rc);
369 return rc;
370}
371
372/**
373 * ecryptfs_miscdev_quit
374 * @euid: effective user id of miscdevess sending quit packet
375 * @pid: miscdevess id of miscdevess sending quit packet
376 *
377 * Returns zero on success; non-zero otherwise
378 */
379static int ecryptfs_miscdev_quit(uid_t euid, pid_t pid)
380{
381 int rc;
382
383 rc = ecryptfs_process_quit(euid, pid);
384 if (rc)
385 printk(KERN_WARNING
386 "Error processing QUIT message; rc = [%d]\n", rc);
387 return rc;
388}
389
390/**
391 * ecryptfs_miscdev_response - miscdevess response to message previously sent to daemon
392 * @data: Bytes comprising struct ecryptfs_message
393 * @data_size: sizeof(struct ecryptfs_message) + data len
394 * @euid: Effective user id of miscdevess sending the miscdev response
395 * @pid: Miscdevess id of miscdevess sending the miscdev response
396 * @seq: Sequence number for miscdev response packet
397 *
398 * Returns zero on success; non-zero otherwise
399 */
400static int ecryptfs_miscdev_response(char *data, size_t data_size,
401 uid_t euid, pid_t pid, u32 seq)
402{
403 struct ecryptfs_message *msg = (struct ecryptfs_message *)data;
404 int rc;
405
406 if ((sizeof(*msg) + msg->data_len) != data_size) {
407 printk(KERN_WARNING "%s: (sizeof(*msg) + msg->data_len) = "
408 "[%Zd]; data_size = [%Zd]. Invalid packet.\n", __func__,
409 (sizeof(*msg) + msg->data_len), data_size);
410 rc = -EINVAL;
411 goto out;
412 }
413 rc = ecryptfs_process_response(msg, euid, pid, seq);
414 if (rc)
415 printk(KERN_ERR
416 "Error processing response message; rc = [%d]\n", rc);
417out:
418 return rc;
419}
420
421/**
422 * ecryptfs_miscdev_write - handle write to daemon miscdev handle
423 * @file: File for misc dev handle (ignored)
424 * @buf: Buffer containing user data
425 * @count: Amount of data in @buf
426 * @ppos: Pointer to offset in file (ignored)
427 *
428 * miscdevfs packet format:
429 * Octet 0: Type
430 * Octets 1-4: network byte order msg_ctx->counter (0's for non-response)
431 * Octets 5-N0: Size of struct ecryptfs_message to follow
432 * Octets N0-N1: struct ecryptfs_message (including data)
433 *
434 * Returns the number of bytes read from @buf
435 */
436static ssize_t
437ecryptfs_miscdev_write(struct file *file, const char __user *buf,
438 size_t count, loff_t *ppos)
439{
440 u32 counter_nbo, seq;
441 size_t packet_size, packet_size_length, i;
442 ssize_t sz = 0;
443 char *data;
444 int rc;
445
446 if (count == 0)
447 goto out;
448 data = kmalloc(count, GFP_KERNEL);
449 if (!data) {
450 printk(KERN_ERR "%s: Out of memory whilst attempting to "
451 "kmalloc([%Zd], GFP_KERNEL)\n", __func__, count);
452 goto out;
453 }
454 rc = copy_from_user(data, buf, count);
455 if (rc) {
456 printk(KERN_ERR "%s: copy_from_user returned error [%d]\n",
457 __func__, rc);
458 goto out_free;
459 }
460 sz = count;
461 i = 0;
462 switch (data[i++]) {
463 case ECRYPTFS_MSG_RESPONSE:
464 if (count < (1 + 4 + 1 + sizeof(struct ecryptfs_message))) {
465 printk(KERN_WARNING "%s: Minimum acceptable packet "
466 "size is [%Zd], but amount of data written is "
467 "only [%Zd]. Discarding response packet.\n",
468 __func__,
469 (1 + 4 + 1 + sizeof(struct ecryptfs_message)),
470 count);
471 goto out_free;
472 }
473 memcpy((char *)&counter_nbo, &data[i], 4);
474 seq = be32_to_cpu(counter_nbo);
475 i += 4;
476 rc = ecryptfs_parse_packet_length(&data[i], &packet_size,
477 &packet_size_length);
478 if (rc) {
479 printk(KERN_WARNING "%s: Error parsing packet length; "
480 "rc = [%d]\n", __func__, rc);
481 goto out_free;
482 }
483 i += packet_size_length;
484 if ((1 + 4 + packet_size_length + packet_size) != count) {
485 printk(KERN_WARNING "%s: (1 + packet_size_length([%Zd])"
486 " + packet_size([%Zd]))([%Zd]) != "
487 "count([%Zd]). Invalid packet format.\n",
488 __func__, packet_size_length, packet_size,
489 (1 + packet_size_length + packet_size), count);
490 goto out_free;
491 }
492 rc = ecryptfs_miscdev_response(&data[i], packet_size,
493 current->euid,
494 current->pid, seq);
495 if (rc)
496 printk(KERN_WARNING "%s: Failed to deliver miscdev "
497 "response to requesting operation; rc = [%d]\n",
498 __func__, rc);
499 break;
500 case ECRYPTFS_MSG_HELO:
501 rc = ecryptfs_miscdev_helo(current->euid, current->pid);
502 if (rc) {
503 printk(KERN_ERR "%s: Error attempting to process "
504 "helo from pid [%d]; rc = [%d]\n", __func__,
505 current->pid, rc);
506 goto out_free;
507 }
508 break;
509 case ECRYPTFS_MSG_QUIT:
510 rc = ecryptfs_miscdev_quit(current->euid, current->pid);
511 if (rc) {
512 printk(KERN_ERR "%s: Error attempting to process "
513 "quit from pid [%d]; rc = [%d]\n", __func__,
514 current->pid, rc);
515 goto out_free;
516 }
517 break;
518 default:
519 ecryptfs_printk(KERN_WARNING, "Dropping miscdev "
520 "message of unrecognized type [%d]\n",
521 data[0]);
522 break;
523 }
524out_free:
525 kfree(data);
526out:
527 return sz;
528}
529
530
531static const struct file_operations ecryptfs_miscdev_fops = {
532 .open = ecryptfs_miscdev_open,
533 .poll = ecryptfs_miscdev_poll,
534 .read = ecryptfs_miscdev_read,
535 .write = ecryptfs_miscdev_write,
536 .release = ecryptfs_miscdev_release,
537};
538
539static struct miscdevice ecryptfs_miscdev = {
540 .minor = MISC_DYNAMIC_MINOR,
541 .name = "ecryptfs",
542 .fops = &ecryptfs_miscdev_fops
543};
544
545/**
546 * ecryptfs_init_ecryptfs_miscdev
547 *
548 * Messages sent to the userspace daemon from the kernel are placed on
549 * a queue associated with the daemon. The next read against the
550 * miscdev handle by that daemon will return the oldest message placed
551 * on the message queue for the daemon.
552 *
553 * Returns zero on success; non-zero otherwise
554 */
555int ecryptfs_init_ecryptfs_miscdev(void)
556{
557 int rc;
558
559 atomic_set(&ecryptfs_num_miscdev_opens, 0);
560 mutex_lock(&ecryptfs_daemon_hash_mux);
561 rc = misc_register(&ecryptfs_miscdev);
562 if (rc)
563 printk(KERN_ERR "%s: Failed to register miscellaneous device "
564 "for communications with userspace daemons; rc = [%d]\n",
565 __func__, rc);
566 mutex_unlock(&ecryptfs_daemon_hash_mux);
567 return rc;
568}
569
570/**
571 * ecryptfs_destroy_ecryptfs_miscdev
572 *
573 * All of the daemons must be exorcised prior to calling this
574 * function.
575 */
576void ecryptfs_destroy_ecryptfs_miscdev(void)
577{
578 BUG_ON(atomic_read(&ecryptfs_num_miscdev_opens) != 0);
579 misc_deregister(&ecryptfs_miscdev);
580}