diff options
Diffstat (limited to 'fs/gfs2/daemon.c')
-rw-r--r-- | fs/gfs2/daemon.c | 225 |
1 files changed, 225 insertions, 0 deletions
diff --git a/fs/gfs2/daemon.c b/fs/gfs2/daemon.c new file mode 100644 index 000000000000..cff8d5368d21 --- /dev/null +++ b/fs/gfs2/daemon.c | |||
@@ -0,0 +1,225 @@ | |||
1 | /* | ||
2 | * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. | ||
3 | * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. | ||
4 | * | ||
5 | * This copyrighted material is made available to anyone wishing to use, | ||
6 | * modify, copy, or redistribute it subject to the terms and conditions | ||
7 | * of the GNU General Public License v.2. | ||
8 | */ | ||
9 | |||
10 | #include <linux/sched.h> | ||
11 | #include <linux/slab.h> | ||
12 | #include <linux/spinlock.h> | ||
13 | #include <linux/completion.h> | ||
14 | #include <linux/buffer_head.h> | ||
15 | #include <linux/kthread.h> | ||
16 | #include <linux/delay.h> | ||
17 | #include <asm/semaphore.h> | ||
18 | |||
19 | #include "gfs2.h" | ||
20 | #include "daemon.h" | ||
21 | #include "glock.h" | ||
22 | #include "log.h" | ||
23 | #include "quota.h" | ||
24 | #include "recovery.h" | ||
25 | #include "super.h" | ||
26 | #include "unlinked.h" | ||
27 | |||
28 | /* This uses schedule_timeout() instead of msleep() because it's good for | ||
29 | the daemons to wake up more often than the timeout when unmounting so | ||
30 | the user's unmount doesn't sit there forever. | ||
31 | |||
32 | The kthread functions used to start these daemons block and flush signals. */ | ||
33 | |||
34 | /** | ||
35 | * gfs2_scand - Look for cached glocks and inodes to toss from memory | ||
36 | * @sdp: Pointer to GFS2 superblock | ||
37 | * | ||
38 | * One of these daemons runs, finding candidates to add to sd_reclaim_list. | ||
39 | * See gfs2_glockd() | ||
40 | */ | ||
41 | |||
42 | int gfs2_scand(void *data) | ||
43 | { | ||
44 | struct gfs2_sbd *sdp = (struct gfs2_sbd *)data; | ||
45 | unsigned long t; | ||
46 | |||
47 | while (!kthread_should_stop()) { | ||
48 | gfs2_scand_internal(sdp); | ||
49 | t = gfs2_tune_get(sdp, gt_scand_secs) * HZ; | ||
50 | schedule_timeout_interruptible(t); | ||
51 | } | ||
52 | |||
53 | return 0; | ||
54 | } | ||
55 | |||
56 | /** | ||
57 | * gfs2_glockd - Reclaim unused glock structures | ||
58 | * @sdp: Pointer to GFS2 superblock | ||
59 | * | ||
60 | * One or more of these daemons run, reclaiming glocks on sd_reclaim_list. | ||
61 | * Number of daemons can be set by user, with num_glockd mount option. | ||
62 | */ | ||
63 | |||
64 | int gfs2_glockd(void *data) | ||
65 | { | ||
66 | struct gfs2_sbd *sdp = (struct gfs2_sbd *)data; | ||
67 | DECLARE_WAITQUEUE(wait_chan, current); | ||
68 | |||
69 | while (!kthread_should_stop()) { | ||
70 | while (atomic_read(&sdp->sd_reclaim_count)) | ||
71 | gfs2_reclaim_glock(sdp); | ||
72 | |||
73 | set_current_state(TASK_INTERRUPTIBLE); | ||
74 | add_wait_queue(&sdp->sd_reclaim_wq, &wait_chan); | ||
75 | if (!atomic_read(&sdp->sd_reclaim_count) && | ||
76 | !kthread_should_stop()) | ||
77 | schedule(); | ||
78 | remove_wait_queue(&sdp->sd_reclaim_wq, &wait_chan); | ||
79 | set_current_state(TASK_RUNNING); | ||
80 | } | ||
81 | |||
82 | return 0; | ||
83 | } | ||
84 | |||
85 | /** | ||
86 | * gfs2_recoverd - Recover dead machine's journals | ||
87 | * @sdp: Pointer to GFS2 superblock | ||
88 | * | ||
89 | */ | ||
90 | |||
91 | int gfs2_recoverd(void *data) | ||
92 | { | ||
93 | struct gfs2_sbd *sdp = (struct gfs2_sbd *)data; | ||
94 | unsigned long t; | ||
95 | |||
96 | while (!kthread_should_stop()) { | ||
97 | gfs2_check_journals(sdp); | ||
98 | t = gfs2_tune_get(sdp, gt_recoverd_secs) * HZ; | ||
99 | schedule_timeout_interruptible(t); | ||
100 | } | ||
101 | |||
102 | return 0; | ||
103 | } | ||
104 | |||
105 | /** | ||
106 | * gfs2_logd - Update log tail as Active Items get flushed to in-place blocks | ||
107 | * @sdp: Pointer to GFS2 superblock | ||
108 | * | ||
109 | * Also, periodically check to make sure that we're using the most recent | ||
110 | * journal index. | ||
111 | */ | ||
112 | |||
113 | int gfs2_logd(void *data) | ||
114 | { | ||
115 | struct gfs2_sbd *sdp = (struct gfs2_sbd *)data; | ||
116 | struct gfs2_holder ji_gh; | ||
117 | unsigned long t; | ||
118 | |||
119 | while (!kthread_should_stop()) { | ||
120 | /* Advance the log tail */ | ||
121 | |||
122 | t = sdp->sd_log_flush_time + | ||
123 | gfs2_tune_get(sdp, gt_log_flush_secs) * HZ; | ||
124 | |||
125 | gfs2_ail1_empty(sdp, DIO_ALL); | ||
126 | |||
127 | if (time_after_eq(jiffies, t)) { | ||
128 | gfs2_log_flush(sdp); | ||
129 | sdp->sd_log_flush_time = jiffies; | ||
130 | } | ||
131 | |||
132 | /* Check for latest journal index */ | ||
133 | |||
134 | t = sdp->sd_jindex_refresh_time + | ||
135 | gfs2_tune_get(sdp, gt_jindex_refresh_secs) * HZ; | ||
136 | |||
137 | if (time_after_eq(jiffies, t)) { | ||
138 | if (!gfs2_jindex_hold(sdp, &ji_gh)) | ||
139 | gfs2_glock_dq_uninit(&ji_gh); | ||
140 | sdp->sd_jindex_refresh_time = jiffies; | ||
141 | } | ||
142 | |||
143 | t = gfs2_tune_get(sdp, gt_logd_secs) * HZ; | ||
144 | schedule_timeout_interruptible(t); | ||
145 | } | ||
146 | |||
147 | return 0; | ||
148 | } | ||
149 | |||
150 | /** | ||
151 | * gfs2_quotad - Write cached quota changes into the quota file | ||
152 | * @sdp: Pointer to GFS2 superblock | ||
153 | * | ||
154 | */ | ||
155 | |||
156 | int gfs2_quotad(void *data) | ||
157 | { | ||
158 | struct gfs2_sbd *sdp = (struct gfs2_sbd *)data; | ||
159 | unsigned long t; | ||
160 | int error; | ||
161 | |||
162 | while (!kthread_should_stop()) { | ||
163 | /* Update the master statfs file */ | ||
164 | |||
165 | t = sdp->sd_statfs_sync_time + | ||
166 | gfs2_tune_get(sdp, gt_statfs_quantum) * HZ; | ||
167 | |||
168 | if (time_after_eq(jiffies, t)) { | ||
169 | error = gfs2_statfs_sync(sdp); | ||
170 | if (error && | ||
171 | error != -EROFS && | ||
172 | !test_bit(SDF_SHUTDOWN, &sdp->sd_flags)) | ||
173 | fs_err(sdp, "quotad: (1) error=%d\n", error); | ||
174 | sdp->sd_statfs_sync_time = jiffies; | ||
175 | } | ||
176 | |||
177 | /* Update quota file */ | ||
178 | |||
179 | t = sdp->sd_quota_sync_time + | ||
180 | gfs2_tune_get(sdp, gt_quota_quantum) * HZ; | ||
181 | |||
182 | if (time_after_eq(jiffies, t)) { | ||
183 | error = gfs2_quota_sync(sdp); | ||
184 | if (error && | ||
185 | error != -EROFS && | ||
186 | !test_bit(SDF_SHUTDOWN, &sdp->sd_flags)) | ||
187 | fs_err(sdp, "quotad: (2) error=%d\n", error); | ||
188 | sdp->sd_quota_sync_time = jiffies; | ||
189 | } | ||
190 | |||
191 | gfs2_quota_scan(sdp); | ||
192 | |||
193 | t = gfs2_tune_get(sdp, gt_quotad_secs) * HZ; | ||
194 | schedule_timeout_interruptible(t); | ||
195 | } | ||
196 | |||
197 | return 0; | ||
198 | } | ||
199 | |||
200 | /** | ||
201 | * gfs2_inoded - Deallocate unlinked inodes | ||
202 | * @sdp: Pointer to GFS2 superblock | ||
203 | * | ||
204 | */ | ||
205 | |||
206 | int gfs2_inoded(void *data) | ||
207 | { | ||
208 | struct gfs2_sbd *sdp = (struct gfs2_sbd *)data; | ||
209 | unsigned long t; | ||
210 | int error; | ||
211 | |||
212 | while (!kthread_should_stop()) { | ||
213 | error = gfs2_unlinked_dealloc(sdp); | ||
214 | if (error && | ||
215 | error != -EROFS && | ||
216 | !test_bit(SDF_SHUTDOWN, &sdp->sd_flags)) | ||
217 | fs_err(sdp, "inoded: error = %d\n", error); | ||
218 | |||
219 | t = gfs2_tune_get(sdp, gt_inoded_secs) * HZ; | ||
220 | schedule_timeout_interruptible(t); | ||
221 | } | ||
222 | |||
223 | return 0; | ||
224 | } | ||
225 | |||