Blame view

fs/lockd/clntlock.c 6.88 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
  /*
   * linux/fs/lockd/clntlock.c
   *
   * Lock handling for the client side NLM implementation
   *
   * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
   */
  
  #include <linux/module.h>
  #include <linux/types.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
11
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
12
13
14
15
16
  #include <linux/time.h>
  #include <linux/nfs_fs.h>
  #include <linux/sunrpc/clnt.h>
  #include <linux/sunrpc/svc.h>
  #include <linux/lockd/lockd.h>
df94f000c   Jeff Layton   lockd: convert re...
17
  #include <linux/kthread.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
  
  #define NLMDBG_FACILITY		NLMDBG_CLIENT
  
  /*
   * Local function prototypes
   */
  static int			reclaimer(void *ptr);
  
  /*
   * The following functions handle blocking and granting from the
   * client perspective.
   */
  
  /*
   * This is the representation of a blocked client lock.
   */
  struct nlm_wait {
4f15e2b1f   Trond Myklebust   [PATCH] NLM: clea...
35
  	struct list_head	b_list;		/* linked list */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
36
37
38
39
  	wait_queue_head_t	b_wait;		/* where to wait on */
  	struct nlm_host *	b_host;
  	struct file_lock *	b_lock;		/* local file lock */
  	unsigned short		b_reclaim;	/* got to reclaim lock */
e8c5c045d   Al Viro   [PATCH] lockd end...
40
  	__be32			b_status;	/* grant callback status */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
41
  };
4f15e2b1f   Trond Myklebust   [PATCH] NLM: clea...
42
  static LIST_HEAD(nlm_blocked);
63185942c   Bryan Schumaker   lockd: Remove BKL...
43
  static DEFINE_SPINLOCK(nlm_blocked_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
44

52c4044d0   Chuck Lever   NLM: Introduce ex...
45
46
  /**
   * nlmclnt_init - Set up per-NFS mount point lockd data structures
883bb163f   Chuck Lever   NLM: Introduce an...
47
   * @nlm_init: pointer to arguments structure
52c4044d0   Chuck Lever   NLM: Introduce ex...
48
49
50
51
   *
   * Returns pointer to an appropriate nlm_host struct,
   * or an ERR_PTR value.
   */
883bb163f   Chuck Lever   NLM: Introduce an...
52
  struct nlm_host *nlmclnt_init(const struct nlmclnt_initdata *nlm_init)
52c4044d0   Chuck Lever   NLM: Introduce ex...
53
54
  {
  	struct nlm_host *host;
883bb163f   Chuck Lever   NLM: Introduce an...
55
  	u32 nlm_version = (nlm_init->nfs_version == 2) ? 1 : 4;
52c4044d0   Chuck Lever   NLM: Introduce ex...
56
  	int status;
26a414092   Chuck Lever   NLM: Remove "prot...
57
  	status = lockd_up();
52c4044d0   Chuck Lever   NLM: Introduce ex...
58
59
  	if (status < 0)
  		return ERR_PTR(status);
d7d204403   Chuck Lever   lockd: Adjust nlm...
60
  	host = nlmclnt_lookup_host(nlm_init->address, nlm_init->addrlen,
883bb163f   Chuck Lever   NLM: Introduce an...
61
  				   nlm_init->protocol, nlm_version,
0cb2659b8   Chuck Lever   NLM: allow lockd ...
62
  				   nlm_init->hostname, nlm_init->noresvport);
52c4044d0   Chuck Lever   NLM: Introduce ex...
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
  	if (host == NULL) {
  		lockd_down();
  		return ERR_PTR(-ENOLCK);
  	}
  
  	return host;
  }
  EXPORT_SYMBOL_GPL(nlmclnt_init);
  
  /**
   * nlmclnt_done - Release resources allocated by nlmclnt_init()
   * @host: nlm_host structure reserved by nlmclnt_init()
   *
   */
  void nlmclnt_done(struct nlm_host *host)
  {
8ea6ecc8b   Chuck Lever   lockd: Create cli...
79
  	nlmclnt_release_host(host);
52c4044d0   Chuck Lever   NLM: Introduce ex...
80
81
82
  	lockd_down();
  }
  EXPORT_SYMBOL_GPL(nlmclnt_done);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
83
  /*
ecdbf769b   Trond Myklebust   [PATCH] NLM: fix ...
84
   * Queue up a lock for blocking so that the GRANTED request can see it
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
85
   */
3a649b884   Trond Myklebust   NLM: Simplify cli...
86
  struct nlm_wait *nlmclnt_prepare_block(struct nlm_host *host, struct file_lock *fl)
ecdbf769b   Trond Myklebust   [PATCH] NLM: fix ...
87
88
  {
  	struct nlm_wait *block;
ecdbf769b   Trond Myklebust   [PATCH] NLM: fix ...
89
  	block = kmalloc(sizeof(*block), GFP_KERNEL);
3a649b884   Trond Myklebust   NLM: Simplify cli...
90
91
92
93
  	if (block != NULL) {
  		block->b_host = host;
  		block->b_lock = fl;
  		init_waitqueue_head(&block->b_wait);
e8c5c045d   Al Viro   [PATCH] lockd end...
94
  		block->b_status = nlm_lck_blocked;
63185942c   Bryan Schumaker   lockd: Remove BKL...
95
96
  
  		spin_lock(&nlm_blocked_lock);
3a649b884   Trond Myklebust   NLM: Simplify cli...
97
  		list_add(&block->b_list, &nlm_blocked);
63185942c   Bryan Schumaker   lockd: Remove BKL...
98
  		spin_unlock(&nlm_blocked_lock);
3a649b884   Trond Myklebust   NLM: Simplify cli...
99
100
  	}
  	return block;
ecdbf769b   Trond Myklebust   [PATCH] NLM: fix ...
101
  }
3a649b884   Trond Myklebust   NLM: Simplify cli...
102
  void nlmclnt_finish_block(struct nlm_wait *block)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
103
  {
ecdbf769b   Trond Myklebust   [PATCH] NLM: fix ...
104
105
  	if (block == NULL)
  		return;
63185942c   Bryan Schumaker   lockd: Remove BKL...
106
  	spin_lock(&nlm_blocked_lock);
ecdbf769b   Trond Myklebust   [PATCH] NLM: fix ...
107
  	list_del(&block->b_list);
63185942c   Bryan Schumaker   lockd: Remove BKL...
108
  	spin_unlock(&nlm_blocked_lock);
ecdbf769b   Trond Myklebust   [PATCH] NLM: fix ...
109
110
  	kfree(block);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
111

ecdbf769b   Trond Myklebust   [PATCH] NLM: fix ...
112
113
114
  /*
   * Block on a lock
   */
3a649b884   Trond Myklebust   NLM: Simplify cli...
115
  int nlmclnt_block(struct nlm_wait *block, struct nlm_rqst *req, long timeout)
ecdbf769b   Trond Myklebust   [PATCH] NLM: fix ...
116
  {
ecdbf769b   Trond Myklebust   [PATCH] NLM: fix ...
117
  	long ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
118

ecdbf769b   Trond Myklebust   [PATCH] NLM: fix ...
119
120
121
  	/* A borken server might ask us to block even if we didn't
  	 * request it. Just say no!
  	 */
3a649b884   Trond Myklebust   NLM: Simplify cli...
122
  	if (block == NULL)
ecdbf769b   Trond Myklebust   [PATCH] NLM: fix ...
123
  		return -EAGAIN;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
124
125
126
127
128
129
130
131
132
  
  	/* Go to sleep waiting for GRANT callback. Some servers seem
  	 * to lose callbacks, however, so we're going to poll from
  	 * time to time just to make sure.
  	 *
  	 * For now, the retry frequency is pretty high; normally 
  	 * a 1 minute timeout would do. See the comment before
  	 * nlmclnt_lock for an explanation.
  	 */
ecdbf769b   Trond Myklebust   [PATCH] NLM: fix ...
133
  	ret = wait_event_interruptible_timeout(block->b_wait,
e8c5c045d   Al Viro   [PATCH] lockd end...
134
  			block->b_status != nlm_lck_blocked,
ecdbf769b   Trond Myklebust   [PATCH] NLM: fix ...
135
  			timeout);
3a649b884   Trond Myklebust   NLM: Simplify cli...
136
137
138
139
  	if (ret < 0)
  		return -ERESTARTSYS;
  	req->a_res.status = block->b_status;
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
140
141
142
143
144
  }
  
  /*
   * The server lockd has called us back to tell us the lock was granted
   */
dcff09f12   Chuck Lever   lockd: change nlm...
145
  __be32 nlmclnt_grant(const struct sockaddr *addr, const struct nlm_lock *lock)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
146
  {
5ac5f9d1c   Trond Myklebust   [PATCH] NLM: Fix ...
147
148
  	const struct file_lock *fl = &lock->fl;
  	const struct nfs_fh *fh = &lock->fh;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
149
  	struct nlm_wait	*block;
52921e02a   Al Viro   [PATCH] lockd end...
150
  	__be32 res = nlm_lck_denied;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
151
152
153
154
155
  
  	/*
  	 * Look up blocked request based on arguments. 
  	 * Warning: must not use cookie to match it!
  	 */
63185942c   Bryan Schumaker   lockd: Remove BKL...
156
  	spin_lock(&nlm_blocked_lock);
4f15e2b1f   Trond Myklebust   [PATCH] NLM: clea...
157
  	list_for_each_entry(block, &nlm_blocked, b_list) {
5ac5f9d1c   Trond Myklebust   [PATCH] NLM: Fix ...
158
  		struct file_lock *fl_blocked = block->b_lock;
7bab377fc   Trond Myklebust   lockd: Don't expo...
159
160
161
162
163
164
165
166
167
  		if (fl_blocked->fl_start != fl->fl_start)
  			continue;
  		if (fl_blocked->fl_end != fl->fl_end)
  			continue;
  		/*
  		 * Careful! The NLM server will return the 32-bit "pid" that
  		 * we put on the wire: in this case the lockowner "pid".
  		 */
  		if (fl_blocked->fl_u.nfs_fl.owner->pid != lock->svid)
5ac5f9d1c   Trond Myklebust   [PATCH] NLM: Fix ...
168
  			continue;
4516fc045   Jeff Layton   sunrpc: add routi...
169
  		if (!rpc_cmp_addr(nlm_addr(block->b_host), addr))
5ac5f9d1c   Trond Myklebust   [PATCH] NLM: Fix ...
170
  			continue;
225a719f7   Josef Sipek   [PATCH] struct pa...
171
  		if (nfs_compare_fh(NFS_FH(fl_blocked->fl_file->f_path.dentry->d_inode) ,fh) != 0)
5ac5f9d1c   Trond Myklebust   [PATCH] NLM: Fix ...
172
173
174
175
  			continue;
  		/* Alright, we found a lock. Set the return status
  		 * and wake up the caller
  		 */
e8c5c045d   Al Viro   [PATCH] lockd end...
176
  		block->b_status = nlm_granted;
5ac5f9d1c   Trond Myklebust   [PATCH] NLM: Fix ...
177
178
  		wake_up(&block->b_wait);
  		res = nlm_granted;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
179
  	}
63185942c   Bryan Schumaker   lockd: Remove BKL...
180
  	spin_unlock(&nlm_blocked_lock);
ecdbf769b   Trond Myklebust   [PATCH] NLM: fix ...
181
  	return res;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
182
183
184
185
186
187
188
189
  }
  
  /*
   * The following procedures deal with the recovery of locks after a
   * server crash.
   */
  
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
190
191
192
193
   * Reclaim all locks on server host. We do this by spawning a separate
   * reclaimer thread.
   */
  void
5c8dd29ca   Olaf Kirch   [PATCH] knfsd: lo...
194
  nlmclnt_recovery(struct nlm_host *host)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
195
  {
df94f000c   Jeff Layton   lockd: convert re...
196
  	struct task_struct *task;
28df955a2   Trond Myklebust   NLM: Fix reclaim ...
197
  	if (!host->h_reclaiming++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
198
  		nlm_get_host(host);
df94f000c   Jeff Layton   lockd: convert re...
199
200
201
202
203
204
  		task = kthread_run(reclaimer, host, "%s-reclaim", host->h_name);
  		if (IS_ERR(task))
  			printk(KERN_ERR "lockd: unable to spawn reclaimer "
  				"thread. Locks for %s won't be reclaimed! "
  				"(%ld)
  ", host->h_name, PTR_ERR(task));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
205
206
207
208
209
210
211
212
  	}
  }
  
  static int
  reclaimer(void *ptr)
  {
  	struct nlm_host	  *host = (struct nlm_host *) ptr;
  	struct nlm_wait	  *block;
26bcbf965   Christoph Hellwig   lockd: stop abusi...
213
  	struct file_lock *fl, *next;
28df955a2   Trond Myklebust   NLM: Fix reclaim ...
214
  	u32 nsmstate;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
215

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
216
  	allow_signal(SIGKILL);
5c8dd29ca   Olaf Kirch   [PATCH] knfsd: lo...
217
  	down_write(&host->h_rwsem);
26a414092   Chuck Lever   NLM: Remove "prot...
218
  	lockd_up();	/* note: this cannot fail as lockd is already running */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
219

d019bcf0e   Adrian Bunk   [PATCH] fs/lockd/...
220
221
  	dprintk("lockd: reclaiming locks for host %s
  ", host->h_name);
5c8dd29ca   Olaf Kirch   [PATCH] knfsd: lo...
222

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
223
  restart:
28df955a2   Trond Myklebust   NLM: Fix reclaim ...
224
  	nsmstate = host->h_nsmstate;
5c8dd29ca   Olaf Kirch   [PATCH] knfsd: lo...
225
226
227
228
  
  	/* Force a portmap getport - the peer's lockd will
  	 * most likely end up on a different port.
  	 */
0ade060ee   Olaf Kirch   [PATCH] knfsd: lo...
229
  	host->h_nextrebind = jiffies;
5c8dd29ca   Olaf Kirch   [PATCH] knfsd: lo...
230
231
232
233
  	nlm_rebind_host(host);
  
  	/* First, reclaim all locks that have been granted. */
  	list_splice_init(&host->h_granted, &host->h_reclaim);
26bcbf965   Christoph Hellwig   lockd: stop abusi...
234
  	list_for_each_entry_safe(fl, next, &host->h_reclaim, fl_u.nfs_fl.list) {
4c060b531   Trond Myklebust   lockd: Fix Oopses...
235
  		list_del_init(&fl->fl_u.nfs_fl.list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
236

df94f000c   Jeff Layton   lockd: convert re...
237
238
239
240
241
242
  		/*
  		 * sending this thread a SIGKILL will result in any unreclaimed
  		 * locks being removed from the h_granted list. This means that
  		 * the kernel will not attempt to reclaim them again if a new
  		 * reclaimer thread is spawned for this host.
  		 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
243
  		if (signalled())
4c060b531   Trond Myklebust   lockd: Fix Oopses...
244
  			continue;
28df955a2   Trond Myklebust   NLM: Fix reclaim ...
245
246
247
248
249
  		if (nlmclnt_reclaim(host, fl) != 0)
  			continue;
  		list_add_tail(&fl->fl_u.nfs_fl.list, &host->h_granted);
  		if (host->h_nsmstate != nsmstate) {
  			/* Argh! The server rebooted again! */
28df955a2   Trond Myklebust   NLM: Fix reclaim ...
250
251
  			goto restart;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
252
  	}
5c8dd29ca   Olaf Kirch   [PATCH] knfsd: lo...
253
254
255
  
  	host->h_reclaiming = 0;
  	up_write(&host->h_rwsem);
d019bcf0e   Adrian Bunk   [PATCH] fs/lockd/...
256
257
  	dprintk("NLM: done reclaiming locks for host %s
  ", host->h_name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
258
259
  
  	/* Now, wake up all processes that sleep on a blocked lock */
63185942c   Bryan Schumaker   lockd: Remove BKL...
260
  	spin_lock(&nlm_blocked_lock);
4f15e2b1f   Trond Myklebust   [PATCH] NLM: clea...
261
  	list_for_each_entry(block, &nlm_blocked, b_list) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
262
  		if (block->b_host == host) {
e8c5c045d   Al Viro   [PATCH] lockd end...
263
  			block->b_status = nlm_lck_denied_grace_period;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
264
265
266
  			wake_up(&block->b_wait);
  		}
  	}
63185942c   Bryan Schumaker   lockd: Remove BKL...
267
  	spin_unlock(&nlm_blocked_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
268
269
  
  	/* Release host handle after use */
8ea6ecc8b   Chuck Lever   lockd: Create cli...
270
  	nlmclnt_release_host(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
271
  	lockd_down();
df94f000c   Jeff Layton   lockd: convert re...
272
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
273
  }