1
2
3
4
5
6
7
8
9#define __KERNEL_SYSCALLS__
10
11#include <linux/module.h>
12#include <linux/types.h>
13#include <linux/sched.h>
14#include <linux/nfs_fs.h>
15#include <linux/unistd.h>
16#include <linux/sunrpc/clnt.h>
17#include <linux/sunrpc/svc.h>
18#include <linux/lockd/lockd.h>
19#include <linux/smp_lock.h>
20
21#define NLMDBG_FACILITY NLMDBG_CLIENT
22
23
24
25
26static int reclaimer(void *ptr);
27
28
29
30
31
32
33
34
35
36struct nlm_wait {
37 struct nlm_wait * b_next;
38 wait_queue_head_t b_wait;
39 struct nlm_host * b_host;
40 struct file_lock * b_lock;
41 unsigned short b_reclaim;
42 u32 b_status;
43};
44
45static struct nlm_wait * nlm_blocked;
46
47
48
49
50int
51nlmclnt_block(struct nlm_host *host, struct file_lock *fl, u32 *statp)
52{
53 struct nlm_wait block, **head;
54 int err;
55 u32 pstate;
56
57 block.b_host = host;
58 block.b_lock = fl;
59 init_waitqueue_head(&block.b_wait);
60 block.b_status = NLM_LCK_BLOCKED;
61 block.b_next = nlm_blocked;
62 nlm_blocked = █
63
64
65 pstate = host->h_state;
66
67
68
69
70
71
72
73
74
75 sleep_on_timeout(&block.b_wait, 30*HZ);
76
77 for (head = &nlm_blocked; *head; head = &(*head)->b_next) {
78 if (*head == &block) {
79 *head = block.b_next;
80 break;
81 }
82 }
83
84 if (!signalled()) {
85 *statp = block.b_status;
86 return 0;
87 }
88
89
90
91
92 if (pstate == host->h_state && (err = nlmclnt_cancel(host, fl)) < 0)
93 printk(KERN_NOTICE
94 "lockd: CANCEL call failed (errno %d)\n", -err);
95
96 return -ERESTARTSYS;
97}
98
99
100
101
102u32
103nlmclnt_grant(struct nlm_lock *lock)
104{
105 struct nlm_wait *block;
106
107
108
109
110
111 for (block = nlm_blocked; block; block = block->b_next) {
112 if (nlm_compare_locks(block->b_lock, &lock->fl))
113 break;
114 }
115
116
117 if (block == NULL)
118 return nlm_lck_denied;
119
120
121
122
123 block->b_status = NLM_LCK_GRANTED;
124 wake_up(&block->b_wait);
125
126 return nlm_granted;
127}
128
129
130
131
132
133
134
135
136
137
138
139static
140void nlmclnt_mark_reclaim(struct nlm_host *host)
141{
142 struct file_lock *fl;
143 struct inode *inode;
144 struct list_head *tmp;
145
146 list_for_each(tmp, &file_lock_list) {
147 fl = list_entry(tmp, struct file_lock, fl_link);
148
149 inode = fl->fl_file->f_dentry->d_inode;
150 if (inode->i_sb->s_magic != NFS_SUPER_MAGIC)
151 continue;
152 if (fl->fl_u.nfs_fl.host != host)
153 continue;
154 if (!(fl->fl_u.nfs_fl.flags & NFS_LCK_GRANTED))
155 continue;
156 fl->fl_u.nfs_fl.flags |= NFS_LCK_RECLAIM;
157 }
158}
159
160
161
162
163
164static inline
165void nlmclnt_prepare_reclaim(struct nlm_host *host, u32 newstate)
166{
167 host->h_monitored = 0;
168 host->h_nsmstate = newstate;
169 host->h_state++;
170 host->h_nextrebind = 0;
171 nlm_rebind_host(host);
172 nlmclnt_mark_reclaim(host);
173 dprintk("NLM: reclaiming locks for host %s", host->h_name);
174}
175
176
177
178
179
180void
181nlmclnt_recovery(struct nlm_host *host, u32 newstate)
182{
183 if (host->h_reclaiming++) {
184 if (host->h_nsmstate == newstate)
185 return;
186 nlmclnt_prepare_reclaim(host, newstate);
187 } else {
188 nlmclnt_prepare_reclaim(host, newstate);
189 nlm_get_host(host);
190 MOD_INC_USE_COUNT;
191 if (kernel_thread(reclaimer, host, CLONE_SIGNAL) < 0)
192 MOD_DEC_USE_COUNT;
193 }
194}
195
196static int
197reclaimer(void *ptr)
198{
199 struct nlm_host *host = (struct nlm_host *) ptr;
200 struct nlm_wait *block;
201 struct list_head *tmp;
202 struct file_lock *fl;
203 struct inode *inode;
204
205 daemonize();
206 reparent_to_init();
207 snprintf(current->comm, sizeof(current->comm),
208 "%s-reclaim",
209 host->h_name);
210
211
212
213 lock_kernel();
214 lockd_up();
215
216
217restart:
218 list_for_each(tmp, &file_lock_list) {
219 fl = list_entry(tmp, struct file_lock, fl_link);
220
221 inode = fl->fl_file->f_dentry->d_inode;
222 if (inode->i_sb->s_magic != NFS_SUPER_MAGIC)
223 continue;
224 if (fl->fl_u.nfs_fl.host != host)
225 continue;
226 if (!(fl->fl_u.nfs_fl.flags & NFS_LCK_RECLAIM))
227 continue;
228
229 fl->fl_u.nfs_fl.flags &= ~NFS_LCK_RECLAIM;
230 nlmclnt_reclaim(host, fl);
231 if (signalled())
232 break;
233 goto restart;
234 }
235
236 host->h_reclaiming = 0;
237 wake_up(&host->h_gracewait);
238
239
240 for (block = nlm_blocked; block; block = block->b_next) {
241 if (block->b_host == host) {
242 block->b_status = NLM_LCK_DENIED_GRACE_PERIOD;
243 wake_up(&block->b_wait);
244 }
245 }
246
247
248 nlm_release_host(host);
249 lockd_down();
250 unlock_kernel();
251 MOD_DEC_USE_COUNT;
252
253 return 0;
254}
255