original comment: +Wilson03172004,marked due to this pci host does not support MWI
[linux-2.4.git] / fs / lockd / clntlock.c
1 /*
2  * linux/fs/lockd/clntlock.c
3  *
4  * Lock handling for the client side NLM implementation
5  *
6  * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
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  * Local function prototypes
25  */
26 static int                      reclaimer(void *ptr);
27
28 /*
29  * The following functions handle blocking and granting from the
30  * client perspective.
31  */
32
33 /*
34  * This is the representation of a blocked client lock.
35  */
36 struct nlm_wait {
37         struct nlm_wait *       b_next;         /* linked list */
38         wait_queue_head_t       b_wait;         /* where to wait on */
39         struct nlm_host *       b_host;
40         struct file_lock *      b_lock;         /* local file lock */
41         unsigned short          b_reclaim;      /* got to reclaim lock */
42         u32                     b_status;       /* grant callback status */
43 };
44
45 static struct nlm_wait *        nlm_blocked;
46
47 /*
48  * Block on a lock
49  */
50 int
51 nlmclnt_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    = &block;
63
64         /* Remember pseudo nsm state */
65         pstate = host->h_state;
66
67         /* Go to sleep waiting for GRANT callback. Some servers seem
68          * to lose callbacks, however, so we're going to poll from
69          * time to time just to make sure.
70          *
71          * For now, the retry frequency is pretty high; normally 
72          * a 1 minute timeout would do. See the comment before
73          * nlmclnt_lock for an explanation.
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         /* Okay, we were interrupted. Cancel the pending request
90          * unless the server has rebooted.
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  * The server lockd has called us back to tell us the lock was granted
101  */
102 u32
103 nlmclnt_grant(struct nlm_lock *lock)
104 {
105         struct nlm_wait *block;
106
107         /*
108          * Look up blocked request based on arguments. 
109          * Warning: must not use cookie to match it!
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         /* Ooops, no blocked request found. */
117         if (block == NULL)
118                 return nlm_lck_denied;
119
120         /* Alright, we found the lock. Set the return status and
121          * wake up the caller.
122          */
123         block->b_status = NLM_LCK_GRANTED;
124         wake_up(&block->b_wait);
125
126         return nlm_granted;
127 }
128
129 /*
130  * The following procedures deal with the recovery of locks after a
131  * server crash.
132  */
133
134 /*
135  * Mark the locks for reclaiming.
136  * FIXME: In 2.5 we don't want to iterate through any global file_lock_list.
137  *        Maintain NLM lock reclaiming lists in the nlm_host instead.
138  */
139 static
140 void 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  * Someone has sent us an SM_NOTIFY. Ensure we bind to the new port number,
162  * that we mark locks for reclaiming, and that we bump the pseudo NSM state.
163  */
164 static inline
165 void 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  * Reclaim all locks on server host. We do this by spawning a separate
178  * reclaimer thread.
179  */
180 void
181 nlmclnt_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
196 static int
197 reclaimer(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         /* This one ensures that our parent doesn't terminate while the
212          * reclaim is in progress */
213         lock_kernel();
214         lockd_up();
215
216         /* First, reclaim all locks that have been marked. */
217 restart:
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         /* Now, wake up all processes that sleep on a blocked lock */
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         /* Release host handle after use */
248         nlm_release_host(host);
249         lockd_down();
250         unlock_kernel();
251         MOD_DEC_USE_COUNT;
252
253         return 0;
254 }