serial: Fix wakeup init logic to speed up startup
[zen-stable.git] / fs / ecryptfs / kthread.c
blob69f994a7d5249589bf594adaa4780bca967f08b2
1 /**
2 * eCryptfs: Linux filesystem encryption layer
4 * Copyright (C) 2008 International Business Machines Corp.
5 * Author(s): Michael A. Halcrow <mahalcro@us.ibm.com>
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of the
10 * License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20 * 02111-1307, USA.
23 #include <linux/kthread.h>
24 #include <linux/freezer.h>
25 #include <linux/slab.h>
26 #include <linux/wait.h>
27 #include <linux/mount.h>
28 #include "ecryptfs_kernel.h"
30 struct kmem_cache *ecryptfs_open_req_cache;
32 static struct ecryptfs_kthread_ctl {
33 #define ECRYPTFS_KTHREAD_ZOMBIE 0x00000001
34 u32 flags;
35 struct mutex mux;
36 struct list_head req_list;
37 wait_queue_head_t wait;
38 } ecryptfs_kthread_ctl;
40 static struct task_struct *ecryptfs_kthread;
42 /**
43 * ecryptfs_threadfn
44 * @ignored: ignored
46 * The eCryptfs kernel thread that has the responsibility of getting
47 * the lower file with RW permissions.
49 * Returns zero on success; non-zero otherwise
51 static int ecryptfs_threadfn(void *ignored)
53 set_freezable();
54 while (1) {
55 struct ecryptfs_open_req *req;
57 wait_event_freezable(
58 ecryptfs_kthread_ctl.wait,
59 (!list_empty(&ecryptfs_kthread_ctl.req_list)
60 || kthread_should_stop()));
61 mutex_lock(&ecryptfs_kthread_ctl.mux);
62 if (ecryptfs_kthread_ctl.flags & ECRYPTFS_KTHREAD_ZOMBIE) {
63 mutex_unlock(&ecryptfs_kthread_ctl.mux);
64 goto out;
66 while (!list_empty(&ecryptfs_kthread_ctl.req_list)) {
67 req = list_first_entry(&ecryptfs_kthread_ctl.req_list,
68 struct ecryptfs_open_req,
69 kthread_ctl_list);
70 mutex_lock(&req->mux);
71 list_del(&req->kthread_ctl_list);
72 if (!(req->flags & ECRYPTFS_REQ_ZOMBIE)) {
73 dget(req->lower_dentry);
74 mntget(req->lower_mnt);
75 (*req->lower_file) = dentry_open(
76 req->lower_dentry, req->lower_mnt,
77 (O_RDWR | O_LARGEFILE), current_cred());
78 req->flags |= ECRYPTFS_REQ_PROCESSED;
80 wake_up(&req->wait);
81 mutex_unlock(&req->mux);
83 mutex_unlock(&ecryptfs_kthread_ctl.mux);
85 out:
86 return 0;
89 int __init ecryptfs_init_kthread(void)
91 int rc = 0;
93 mutex_init(&ecryptfs_kthread_ctl.mux);
94 init_waitqueue_head(&ecryptfs_kthread_ctl.wait);
95 INIT_LIST_HEAD(&ecryptfs_kthread_ctl.req_list);
96 ecryptfs_kthread = kthread_run(&ecryptfs_threadfn, NULL,
97 "ecryptfs-kthread");
98 if (IS_ERR(ecryptfs_kthread)) {
99 rc = PTR_ERR(ecryptfs_kthread);
100 printk(KERN_ERR "%s: Failed to create kernel thread; rc = [%d]"
101 "\n", __func__, rc);
103 return rc;
106 void ecryptfs_destroy_kthread(void)
108 struct ecryptfs_open_req *req;
110 mutex_lock(&ecryptfs_kthread_ctl.mux);
111 ecryptfs_kthread_ctl.flags |= ECRYPTFS_KTHREAD_ZOMBIE;
112 list_for_each_entry(req, &ecryptfs_kthread_ctl.req_list,
113 kthread_ctl_list) {
114 mutex_lock(&req->mux);
115 req->flags |= ECRYPTFS_REQ_ZOMBIE;
116 wake_up(&req->wait);
117 mutex_unlock(&req->mux);
119 mutex_unlock(&ecryptfs_kthread_ctl.mux);
120 kthread_stop(ecryptfs_kthread);
121 wake_up(&ecryptfs_kthread_ctl.wait);
125 * ecryptfs_privileged_open
126 * @lower_file: Result of dentry_open by root on lower dentry
127 * @lower_dentry: Lower dentry for file to open
128 * @lower_mnt: Lower vfsmount for file to open
130 * This function gets a r/w file opened againt the lower dentry.
132 * Returns zero on success; non-zero otherwise
134 int ecryptfs_privileged_open(struct file **lower_file,
135 struct dentry *lower_dentry,
136 struct vfsmount *lower_mnt,
137 const struct cred *cred)
139 struct ecryptfs_open_req *req;
140 int flags = O_LARGEFILE;
141 int rc = 0;
143 /* Corresponding dput() and mntput() are done when the
144 * lower file is fput() when all eCryptfs files for the inode are
145 * released. */
146 dget(lower_dentry);
147 mntget(lower_mnt);
148 flags |= IS_RDONLY(lower_dentry->d_inode) ? O_RDONLY : O_RDWR;
149 (*lower_file) = dentry_open(lower_dentry, lower_mnt, flags, cred);
150 if (!IS_ERR(*lower_file))
151 goto out;
152 if (flags & O_RDONLY) {
153 rc = PTR_ERR((*lower_file));
154 goto out;
156 req = kmem_cache_alloc(ecryptfs_open_req_cache, GFP_KERNEL);
157 if (!req) {
158 rc = -ENOMEM;
159 goto out;
161 mutex_init(&req->mux);
162 req->lower_file = lower_file;
163 req->lower_dentry = lower_dentry;
164 req->lower_mnt = lower_mnt;
165 init_waitqueue_head(&req->wait);
166 req->flags = 0;
167 mutex_lock(&ecryptfs_kthread_ctl.mux);
168 if (ecryptfs_kthread_ctl.flags & ECRYPTFS_KTHREAD_ZOMBIE) {
169 rc = -EIO;
170 mutex_unlock(&ecryptfs_kthread_ctl.mux);
171 printk(KERN_ERR "%s: We are in the middle of shutting down; "
172 "aborting privileged request to open lower file\n",
173 __func__);
174 goto out_free;
176 list_add_tail(&req->kthread_ctl_list, &ecryptfs_kthread_ctl.req_list);
177 mutex_unlock(&ecryptfs_kthread_ctl.mux);
178 wake_up(&ecryptfs_kthread_ctl.wait);
179 wait_event(req->wait, (req->flags != 0));
180 mutex_lock(&req->mux);
181 BUG_ON(req->flags == 0);
182 if (req->flags & ECRYPTFS_REQ_DROPPED
183 || req->flags & ECRYPTFS_REQ_ZOMBIE) {
184 rc = -EIO;
185 printk(KERN_WARNING "%s: Privileged open request dropped\n",
186 __func__);
187 goto out_unlock;
189 if (IS_ERR(*req->lower_file))
190 rc = PTR_ERR(*req->lower_file);
191 out_unlock:
192 mutex_unlock(&req->mux);
193 out_free:
194 kmem_cache_free(ecryptfs_open_req_cache, req);
195 out:
196 return rc;