]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blob - fs/afs/kafstimod.c
694344e4d3c7503ca03750549495bc6cad8fef1a
[mirror_ubuntu-zesty-kernel.git] / fs / afs / kafstimod.c
1 /* kafstimod.c: AFS timeout daemon
2 *
3 * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 */
11
12 #include <linux/module.h>
13 #include <linux/init.h>
14 #include <linux/sched.h>
15 #include <linux/completion.h>
16 #include <linux/freezer.h>
17 #include "cell.h"
18 #include "volume.h"
19 #include "kafstimod.h"
20 #include <asm/errno.h>
21 #include "internal.h"
22
23 static DECLARE_COMPLETION(kafstimod_alive);
24 static DECLARE_COMPLETION(kafstimod_dead);
25 static DECLARE_WAIT_QUEUE_HEAD(kafstimod_sleepq);
26 static int kafstimod_die;
27
28 static LIST_HEAD(kafstimod_list);
29 static DEFINE_SPINLOCK(kafstimod_lock);
30
31 static int kafstimod(void *arg);
32
33 /*****************************************************************************/
34 /*
35 * start the timeout daemon
36 */
37 int afs_kafstimod_start(void)
38 {
39 int ret;
40
41 ret = kernel_thread(kafstimod, NULL, 0);
42 if (ret < 0)
43 return ret;
44
45 wait_for_completion(&kafstimod_alive);
46
47 return ret;
48 } /* end afs_kafstimod_start() */
49
50 /*****************************************************************************/
51 /*
52 * stop the timeout daemon
53 */
54 void afs_kafstimod_stop(void)
55 {
56 /* get rid of my daemon */
57 kafstimod_die = 1;
58 wake_up(&kafstimod_sleepq);
59 wait_for_completion(&kafstimod_dead);
60
61 } /* end afs_kafstimod_stop() */
62
63 /*****************************************************************************/
64 /*
65 * timeout processing daemon
66 */
67 static int kafstimod(void *arg)
68 {
69 struct afs_timer *timer;
70
71 DECLARE_WAITQUEUE(myself, current);
72
73 printk("kAFS: Started kafstimod %d\n", current->pid);
74
75 daemonize("kafstimod");
76
77 complete(&kafstimod_alive);
78
79 /* loop around looking for things to attend to */
80 loop:
81 set_current_state(TASK_INTERRUPTIBLE);
82 add_wait_queue(&kafstimod_sleepq, &myself);
83
84 for (;;) {
85 unsigned long jif;
86 signed long timeout;
87
88 /* deal with the server being asked to die */
89 if (kafstimod_die) {
90 remove_wait_queue(&kafstimod_sleepq, &myself);
91 _leave("");
92 complete_and_exit(&kafstimod_dead, 0);
93 }
94
95 try_to_freeze();
96
97 /* discard pending signals */
98 afs_discard_my_signals();
99
100 /* work out the time to elapse before the next event */
101 spin_lock(&kafstimod_lock);
102 if (list_empty(&kafstimod_list)) {
103 timeout = MAX_SCHEDULE_TIMEOUT;
104 }
105 else {
106 timer = list_entry(kafstimod_list.next,
107 struct afs_timer, link);
108 timeout = timer->timo_jif;
109 jif = jiffies;
110
111 if (time_before_eq((unsigned long) timeout, jif))
112 goto immediate;
113
114 else {
115 timeout = (long) timeout - (long) jiffies;
116 }
117 }
118 spin_unlock(&kafstimod_lock);
119
120 schedule_timeout(timeout);
121
122 set_current_state(TASK_INTERRUPTIBLE);
123 }
124
125 /* the thing on the front of the queue needs processing
126 * - we come here with the lock held and timer pointing to the expired
127 * entry
128 */
129 immediate:
130 remove_wait_queue(&kafstimod_sleepq, &myself);
131 set_current_state(TASK_RUNNING);
132
133 _debug("@@@ Begin Timeout of %p", timer);
134
135 /* dequeue the timer */
136 list_del_init(&timer->link);
137 spin_unlock(&kafstimod_lock);
138
139 /* call the timeout function */
140 timer->ops->timed_out(timer);
141
142 _debug("@@@ End Timeout");
143 goto loop;
144
145 } /* end kafstimod() */
146
147 /*****************************************************************************/
148 /*
149 * (re-)queue a timer
150 */
151 void afs_kafstimod_add_timer(struct afs_timer *timer, unsigned long timeout)
152 {
153 struct afs_timer *ptimer;
154 struct list_head *_p;
155
156 _enter("%p,%lu", timer, timeout);
157
158 spin_lock(&kafstimod_lock);
159
160 list_del(&timer->link);
161
162 /* the timer was deferred or reset - put it back in the queue at the
163 * right place */
164 timer->timo_jif = jiffies + timeout;
165
166 list_for_each(_p, &kafstimod_list) {
167 ptimer = list_entry(_p, struct afs_timer, link);
168 if (time_before(timer->timo_jif, ptimer->timo_jif))
169 break;
170 }
171
172 list_add_tail(&timer->link, _p); /* insert before stopping point */
173
174 spin_unlock(&kafstimod_lock);
175
176 wake_up(&kafstimod_sleepq);
177
178 _leave("");
179 } /* end afs_kafstimod_add_timer() */
180
181 /*****************************************************************************/
182 /*
183 * dequeue a timer
184 * - returns 0 if the timer was deleted or -ENOENT if it wasn't queued
185 */
186 int afs_kafstimod_del_timer(struct afs_timer *timer)
187 {
188 int ret = 0;
189
190 _enter("%p", timer);
191
192 spin_lock(&kafstimod_lock);
193
194 if (list_empty(&timer->link))
195 ret = -ENOENT;
196 else
197 list_del_init(&timer->link);
198
199 spin_unlock(&kafstimod_lock);
200
201 wake_up(&kafstimod_sleepq);
202
203 _leave(" = %d", ret);
204 return ret;
205 } /* end afs_kafstimod_del_timer() */