Blame view

fs/lockd/clntproc.c 20.8 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
  /*
   * linux/fs/lockd/clntproc.c
   *
   * RPC procedures for the client side NLM implementation
   *
   * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8
  #include <linux/module.h>
405f55712   Alexey Dobriyan   headers: smp_lock...
9
  #include <linux/smp_lock.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
10
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
11
12
13
14
15
  #include <linux/types.h>
  #include <linux/errno.h>
  #include <linux/fs.h>
  #include <linux/nfs_fs.h>
  #include <linux/utsname.h>
7dfb71030   Nigel Cunningham   [PATCH] Add inclu...
16
  #include <linux/freezer.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
17
18
19
  #include <linux/sunrpc/clnt.h>
  #include <linux/sunrpc/svc.h>
  #include <linux/lockd/lockd.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
20
21
22
  
  #define NLMDBG_FACILITY		NLMDBG_CLIENT
  #define NLMCLNT_GRACE_WAIT	(5*HZ)
ecdbf769b   Trond Myklebust   [PATCH] NLM: fix ...
23
  #define NLMCLNT_POLL_TIMEOUT	(30*HZ)
aaaa99423   Trond Myklebust   NLM: Ensure that ...
24
  #define NLMCLNT_MAX_RETRIES	3
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
25
26
27
28
  
  static int	nlmclnt_test(struct nlm_rqst *, struct file_lock *);
  static int	nlmclnt_lock(struct nlm_rqst *, struct file_lock *);
  static int	nlmclnt_unlock(struct nlm_rqst *, struct file_lock *);
e8c5c045d   Al Viro   [PATCH] lockd end...
29
  static int	nlm_stat_to_errno(__be32 stat);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
30
  static void	nlmclnt_locks_init_private(struct file_lock *fl, struct nlm_host *host);
16fb24252   Trond Myklebust   NLM: Fix argument...
31
  static int	nlmclnt_cancel(struct nlm_host *, int , struct file_lock *);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
32

963d8fe53   Trond Myklebust   RPC: Clean up RPC...
33
34
  static const struct rpc_call_ops nlmclnt_unlock_ops;
  static const struct rpc_call_ops nlmclnt_cancel_ops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35
36
37
  /*
   * Cookie counter for NLM requests
   */
031d869d0   Olaf Kirch   [PATCH] knfsd: ma...
38
  static atomic_t	nlm_cookie = ATOMIC_INIT(0x1234);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39

031d869d0   Olaf Kirch   [PATCH] knfsd: ma...
40
  void nlmclnt_next_cookie(struct nlm_cookie *c)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
41
  {
031d869d0   Olaf Kirch   [PATCH] knfsd: ma...
42
43
44
  	u32	cookie = atomic_inc_return(&nlm_cookie);
  
  	memcpy(c->data, &cookie, 4);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
45
  	c->len=4;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
  }
  
  static struct nlm_lockowner *nlm_get_lockowner(struct nlm_lockowner *lockowner)
  {
  	atomic_inc(&lockowner->count);
  	return lockowner;
  }
  
  static void nlm_put_lockowner(struct nlm_lockowner *lockowner)
  {
  	if (!atomic_dec_and_lock(&lockowner->count, &lockowner->host->h_lock))
  		return;
  	list_del(&lockowner->list);
  	spin_unlock(&lockowner->host->h_lock);
  	nlm_release_host(lockowner->host);
  	kfree(lockowner);
  }
  
  static inline int nlm_pidbusy(struct nlm_host *host, uint32_t pid)
  {
  	struct nlm_lockowner *lockowner;
  	list_for_each_entry(lockowner, &host->h_lockowners, list) {
  		if (lockowner->pid == pid)
  			return -EBUSY;
  	}
  	return 0;
  }
  
  static inline uint32_t __nlm_alloc_pid(struct nlm_host *host)
  {
  	uint32_t res;
  	do {
  		res = host->h_pidcount++;
  	} while (nlm_pidbusy(host, res) < 0);
  	return res;
  }
  
  static struct nlm_lockowner *__nlm_find_lockowner(struct nlm_host *host, fl_owner_t owner)
  {
  	struct nlm_lockowner *lockowner;
  	list_for_each_entry(lockowner, &host->h_lockowners, list) {
  		if (lockowner->owner != owner)
  			continue;
  		return nlm_get_lockowner(lockowner);
  	}
  	return NULL;
  }
  
  static struct nlm_lockowner *nlm_find_lockowner(struct nlm_host *host, fl_owner_t owner)
  {
  	struct nlm_lockowner *res, *new = NULL;
  
  	spin_lock(&host->h_lock);
  	res = __nlm_find_lockowner(host, owner);
  	if (res == NULL) {
  		spin_unlock(&host->h_lock);
f52720ca5   Panagiotis Issaris   [PATCH] fs: Remov...
102
  		new = kmalloc(sizeof(*new), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
103
104
105
106
107
108
109
110
111
112
113
114
115
  		spin_lock(&host->h_lock);
  		res = __nlm_find_lockowner(host, owner);
  		if (res == NULL && new != NULL) {
  			res = new;
  			atomic_set(&new->count, 1);
  			new->owner = owner;
  			new->pid = __nlm_alloc_pid(host);
  			new->host = nlm_get_host(host);
  			list_add(&new->list, &host->h_lockowners);
  			new = NULL;
  		}
  	}
  	spin_unlock(&host->h_lock);
f99d49adf   Jesper Juhl   [PATCH] kfree cle...
116
  	kfree(new);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
117
118
119
120
121
122
123
124
125
126
127
128
  	return res;
  }
  
  /*
   * Initialize arguments for TEST/LOCK/UNLOCK/CANCEL calls
   */
  static void nlmclnt_setlockargs(struct nlm_rqst *req, struct file_lock *fl)
  {
  	struct nlm_args	*argp = &req->a_args;
  	struct nlm_lock	*lock = &argp->lock;
  
  	nlmclnt_next_cookie(&argp->cookie);
225a719f7   Josef Sipek   [PATCH] struct pa...
129
  	memcpy(&lock->fh, NFS_FH(fl->fl_file->f_path.dentry->d_inode), sizeof(struct nfs_fh));
e9ff3990f   Serge E. Hallyn   [PATCH] namespace...
130
  	lock->caller  = utsname()->nodename;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
131
  	lock->oh.data = req->a_owner;
7bab377fc   Trond Myklebust   lockd: Don't expo...
132
133
  	lock->oh.len  = snprintf(req->a_owner, sizeof(req->a_owner), "%u@%s",
  				(unsigned int)fl->fl_u.nfs_fl.owner->pid,
e9ff3990f   Serge E. Hallyn   [PATCH] namespace...
134
  				utsname()->nodename);
7bab377fc   Trond Myklebust   lockd: Don't expo...
135
  	lock->svid = fl->fl_u.nfs_fl.owner->pid;
3a649b884   Trond Myklebust   NLM: Simplify cli...
136
137
138
  	lock->fl.fl_start = fl->fl_start;
  	lock->fl.fl_end = fl->fl_end;
  	lock->fl.fl_type = fl->fl_type;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
139
140
141
142
  }
  
  static void nlmclnt_release_lockargs(struct nlm_rqst *req)
  {
3a649b884   Trond Myklebust   NLM: Simplify cli...
143
  	BUG_ON(req->a_args.lock.fl.fl_ops != NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
144
  }
1093a60ef   Chuck Lever   NLM/NFS: Use cach...
145
146
147
148
149
150
  /**
   * nlmclnt_proc - Perform a single client-side lock request
   * @host: address of a valid nlm_host context representing the NLM server
   * @cmd: fcntl-style file lock operation to perform
   * @fl: address of arguments for the lock operation
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
151
   */
1093a60ef   Chuck Lever   NLM/NFS: Use cach...
152
  int nlmclnt_proc(struct nlm_host *host, int cmd, struct file_lock *fl)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
153
  {
92737230d   Trond Myklebust   NLM: Add nlmclnt_...
154
  	struct nlm_rqst		*call;
1093a60ef   Chuck Lever   NLM/NFS: Use cach...
155
  	int			status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
156

1093a60ef   Chuck Lever   NLM/NFS: Use cach...
157
  	nlm_get_host(host);
92737230d   Trond Myklebust   NLM: Add nlmclnt_...
158
159
160
  	call = nlm_alloc_call(host);
  	if (call == NULL)
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
161

92737230d   Trond Myklebust   NLM: Add nlmclnt_...
162
163
164
  	nlmclnt_locks_init_private(fl, host);
  	/* Set up the argument struct */
  	nlmclnt_setlockargs(call, fl);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
165

5cd973c44   Trond Myklebust   NFSv4/NLM: Push f...
166
  	lock_kernel();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
167
168
169
170
171
172
173
174
175
176
  	if (IS_SETLK(cmd) || IS_SETLKW(cmd)) {
  		if (fl->fl_type != F_UNLCK) {
  			call->a_args.block = IS_SETLKW(cmd) ? 1 : 0;
  			status = nlmclnt_lock(call, fl);
  		} else
  			status = nlmclnt_unlock(call, fl);
  	} else if (IS_GETLK(cmd))
  		status = nlmclnt_test(call, fl);
  	else
  		status = -EINVAL;
92737230d   Trond Myklebust   NLM: Add nlmclnt_...
177
178
  	fl->fl_ops->fl_release_private(fl);
  	fl->fl_ops = NULL;
5cd973c44   Trond Myklebust   NFSv4/NLM: Push f...
179
  	unlock_kernel();
92737230d   Trond Myklebust   NLM: Add nlmclnt_...
180

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
181
182
  	dprintk("lockd: clnt proc returns %d
  ", status);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
183
184
  	return status;
  }
1093a60ef   Chuck Lever   NLM/NFS: Use cach...
185
  EXPORT_SYMBOL_GPL(nlmclnt_proc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
186
187
188
  
  /*
   * Allocate an NLM RPC call struct
92737230d   Trond Myklebust   NLM: Add nlmclnt_...
189
190
191
   *
   * Note: the caller must hold a reference to host. In case of failure,
   * this reference will be released.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
192
   */
92737230d   Trond Myklebust   NLM: Add nlmclnt_...
193
  struct nlm_rqst *nlm_alloc_call(struct nlm_host *host)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
194
195
  {
  	struct nlm_rqst	*call;
36943fa4b   Trond Myklebust   NLM: nlm_alloc_ca...
196
197
198
  	for(;;) {
  		call = kzalloc(sizeof(*call), GFP_KERNEL);
  		if (call != NULL) {
5e7f37a76   Trond Myklebust   NLM/lockd: Add a ...
199
  			atomic_set(&call->a_count, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
200
201
  			locks_init_lock(&call->a_args.lock.fl);
  			locks_init_lock(&call->a_res.lock.fl);
92737230d   Trond Myklebust   NLM: Add nlmclnt_...
202
  			call->a_host = host;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
203
204
  			return call;
  		}
36943fa4b   Trond Myklebust   NLM: nlm_alloc_ca...
205
206
  		if (signalled())
  			break;
92737230d   Trond Myklebust   NLM: Add nlmclnt_...
207
208
  		printk("nlm_alloc_call: failed, waiting for memory
  ");
041e0e3b1   Nishanth Aravamudan   [PATCH] fs: fix-u...
209
  		schedule_timeout_interruptible(5*HZ);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
210
  	}
92737230d   Trond Myklebust   NLM: Add nlmclnt_...
211
  	nlm_release_host(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
212
213
  	return NULL;
  }
92737230d   Trond Myklebust   NLM: Add nlmclnt_...
214
215
  void nlm_release_call(struct nlm_rqst *call)
  {
5e7f37a76   Trond Myklebust   NLM/lockd: Add a ...
216
217
  	if (!atomic_dec_and_test(&call->a_count))
  		return;
92737230d   Trond Myklebust   NLM: Add nlmclnt_...
218
219
220
221
222
223
224
  	nlm_release_host(call->a_host);
  	nlmclnt_release_lockargs(call);
  	kfree(call);
  }
  
  static void nlmclnt_rpc_release(void *data)
  {
a86dc496b   Trond Myklebust   SUNRPC: Remove th...
225
  	lock_kernel();
65fdf7d26   Trond Myklebust   NLM: Fix a bogus ...
226
  	nlm_release_call(data);
a86dc496b   Trond Myklebust   SUNRPC: Remove th...
227
  	unlock_kernel();
92737230d   Trond Myklebust   NLM: Add nlmclnt_...
228
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
229
230
231
232
233
234
235
236
  static int nlm_wait_on_grace(wait_queue_head_t *queue)
  {
  	DEFINE_WAIT(wait);
  	int status = -EINTR;
  
  	prepare_to_wait(queue, &wait, TASK_INTERRUPTIBLE);
  	if (!signalled ()) {
  		schedule_timeout(NLMCLNT_GRACE_WAIT);
3e1d1d28d   Christoph Lameter   [PATCH] Cleanup p...
237
  		try_to_freeze();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
238
239
240
241
242
243
244
245
246
247
248
  		if (!signalled ())
  			status = 0;
  	}
  	finish_wait(queue, &wait);
  	return status;
  }
  
  /*
   * Generic NLM call
   */
  static int
d11d10cc0   Trond Myklebust   NLM/lockd: Ensure...
249
  nlmclnt_call(struct rpc_cred *cred, struct nlm_rqst *req, u32 proc)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
250
251
252
253
254
255
256
257
  {
  	struct nlm_host	*host = req->a_host;
  	struct rpc_clnt	*clnt;
  	struct nlm_args	*argp = &req->a_args;
  	struct nlm_res	*resp = &req->a_res;
  	struct rpc_message msg = {
  		.rpc_argp	= argp,
  		.rpc_resp	= resp,
d11d10cc0   Trond Myklebust   NLM/lockd: Ensure...
258
  		.rpc_cred	= cred,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
  	};
  	int		status;
  
  	dprintk("lockd: call procedure %d on %s
  ",
  			(int)proc, host->h_name);
  
  	do {
  		if (host->h_reclaiming && !argp->reclaim)
  			goto in_grace_period;
  
  		/* If we have no RPC client yet, create one. */
  		if ((clnt = nlm_bind_host(host)) == NULL)
  			return -ENOLCK;
  		msg.rpc_proc = &clnt->cl_procinfo[proc];
  
  		/* Perform the RPC call. If an error occurs, try again */
  		if ((status = rpc_call_sync(clnt, &msg, 0)) < 0) {
  			dprintk("lockd: rpc_call returned error %d
  ", -status);
  			switch (status) {
  			case -EPROTONOSUPPORT:
  				status = -EINVAL;
  				break;
  			case -ECONNREFUSED:
  			case -ETIMEDOUT:
  			case -ENOTCONN:
  				nlm_rebind_host(host);
  				status = -EAGAIN;
  				break;
  			case -ERESTARTSYS:
  				return signalled () ? -EINTR : status;
  			default:
  				break;
  			}
  			break;
  		} else
e8c5c045d   Al Viro   [PATCH] lockd end...
296
  		if (resp->status == nlm_lck_denied_grace_period) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
  			dprintk("lockd: server in grace period
  ");
  			if (argp->reclaim) {
  				printk(KERN_WARNING
  				     "lockd: spurious grace period reject?!
  ");
  				return -ENOLCK;
  			}
  		} else {
  			if (!argp->reclaim) {
  				/* We appear to be out of the grace period */
  				wake_up_all(&host->h_gracewait);
  			}
  			dprintk("lockd: server returns status %d
  ", resp->status);
  			return 0;	/* Okay, call complete */
  		}
  
  in_grace_period:
  		/*
  		 * The server has rebooted and appears to be in the grace
  		 * period during which locks are only allowed to be
  		 * reclaimed.
  		 * We can only back off and try again later.
  		 */
  		status = nlm_wait_on_grace(&host->h_gracewait);
  	} while (status == 0);
  
  	return status;
  }
  
  /*
   * Generic NLM call, async version.
   */
dc9d8d048   Trond Myklebust   NLM/lockd: conver...
331
  static struct rpc_task *__nlm_async_call(struct nlm_rqst *req, u32 proc, struct rpc_message *msg, const struct rpc_call_ops *tk_ops)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
332
333
334
  {
  	struct nlm_host	*host = req->a_host;
  	struct rpc_clnt	*clnt;
dc9d8d048   Trond Myklebust   NLM/lockd: conver...
335
336
337
338
339
340
  	struct rpc_task_setup task_setup_data = {
  		.rpc_message = msg,
  		.callback_ops = tk_ops,
  		.callback_data = req,
  		.flags = RPC_TASK_ASYNC,
  	};
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
341
342
343
344
345
346
  
  	dprintk("lockd: call procedure %d on %s (async)
  ",
  			(int)proc, host->h_name);
  
  	/* If we have no RPC client yet, create one. */
92737230d   Trond Myklebust   NLM: Add nlmclnt_...
347
348
349
  	clnt = nlm_bind_host(host);
  	if (clnt == NULL)
  		goto out_err;
d47166244   Trond Myklebust   lockd: Add helper...
350
  	msg->rpc_proc = &clnt->cl_procinfo[proc];
dc9d8d048   Trond Myklebust   NLM/lockd: conver...
351
  	task_setup_data.rpc_client = clnt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
352

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
353
          /* bootstrap and kick off the async RPC call */
dc9d8d048   Trond Myklebust   NLM/lockd: conver...
354
  	return rpc_run_task(&task_setup_data);
92737230d   Trond Myklebust   NLM: Add nlmclnt_...
355
  out_err:
a995e9eb3   Trond Myklebust   NLM: Fix double f...
356
  	tk_ops->rpc_release(req);
dc9d8d048   Trond Myklebust   NLM/lockd: conver...
357
358
359
360
361
362
363
364
365
366
367
368
  	return ERR_PTR(-ENOLCK);
  }
  
  static int nlm_do_async_call(struct nlm_rqst *req, u32 proc, struct rpc_message *msg, const struct rpc_call_ops *tk_ops)
  {
  	struct rpc_task *task;
  
  	task = __nlm_async_call(req, proc, msg, tk_ops);
  	if (IS_ERR(task))
  		return PTR_ERR(task);
  	rpc_put_task(task);
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
369
  }
dc9d8d048   Trond Myklebust   NLM/lockd: conver...
370
371
372
  /*
   * NLM asynchronous call.
   */
d47166244   Trond Myklebust   lockd: Add helper...
373
374
375
376
377
378
  int nlm_async_call(struct nlm_rqst *req, u32 proc, const struct rpc_call_ops *tk_ops)
  {
  	struct rpc_message msg = {
  		.rpc_argp	= &req->a_args,
  		.rpc_resp	= &req->a_res,
  	};
dc9d8d048   Trond Myklebust   NLM/lockd: conver...
379
  	return nlm_do_async_call(req, proc, &msg, tk_ops);
d47166244   Trond Myklebust   lockd: Add helper...
380
381
382
383
384
385
386
  }
  
  int nlm_async_reply(struct nlm_rqst *req, u32 proc, const struct rpc_call_ops *tk_ops)
  {
  	struct rpc_message msg = {
  		.rpc_argp	= &req->a_res,
  	};
dc9d8d048   Trond Myklebust   NLM/lockd: conver...
387
388
389
390
391
392
393
394
395
396
397
  	return nlm_do_async_call(req, proc, &msg, tk_ops);
  }
  
  /*
   * NLM client asynchronous call.
   *
   * Note that although the calls are asynchronous, and are therefore
   *      guaranteed to complete, we still always attempt to wait for
   *      completion in order to be able to correctly track the lock
   *      state.
   */
d11d10cc0   Trond Myklebust   NLM/lockd: Ensure...
398
  static int nlmclnt_async_call(struct rpc_cred *cred, struct nlm_rqst *req, u32 proc, const struct rpc_call_ops *tk_ops)
dc9d8d048   Trond Myklebust   NLM/lockd: conver...
399
400
401
402
  {
  	struct rpc_message msg = {
  		.rpc_argp	= &req->a_args,
  		.rpc_resp	= &req->a_res,
d11d10cc0   Trond Myklebust   NLM/lockd: Ensure...
403
  		.rpc_cred	= cred,
dc9d8d048   Trond Myklebust   NLM/lockd: conver...
404
405
406
407
408
409
410
411
412
413
  	};
  	struct rpc_task *task;
  	int err;
  
  	task = __nlm_async_call(req, proc, &msg, tk_ops);
  	if (IS_ERR(task))
  		return PTR_ERR(task);
  	err = rpc_wait_for_completion_task(task);
  	rpc_put_task(task);
  	return err;
d47166244   Trond Myklebust   lockd: Add helper...
414
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
415
416
417
418
419
420
421
  /*
   * TEST for the presence of a conflicting lock
   */
  static int
  nlmclnt_test(struct nlm_rqst *req, struct file_lock *fl)
  {
  	int	status;
d11d10cc0   Trond Myklebust   NLM/lockd: Ensure...
422
  	status = nlmclnt_call(nfs_file_cred(fl->fl_file), req, NLMPROC_TEST);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
423
  	if (status < 0)
92737230d   Trond Myklebust   NLM: Add nlmclnt_...
424
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
425

92737230d   Trond Myklebust   NLM: Add nlmclnt_...
426
  	switch (req->a_res.status) {
e8c5c045d   Al Viro   [PATCH] lockd end...
427
  		case nlm_granted:
92737230d   Trond Myklebust   NLM: Add nlmclnt_...
428
429
  			fl->fl_type = F_UNLCK;
  			break;
e8c5c045d   Al Viro   [PATCH] lockd end...
430
  		case nlm_lck_denied:
92737230d   Trond Myklebust   NLM: Add nlmclnt_...
431
432
433
434
  			/*
  			 * Report the conflicting lock back to the application.
  			 */
  			fl->fl_start = req->a_res.lock.fl.fl_start;
d67d1c7bf   Felix Blyakher   nfs: set correct ...
435
  			fl->fl_end = req->a_res.lock.fl.fl_end;
92737230d   Trond Myklebust   NLM: Add nlmclnt_...
436
437
438
439
440
  			fl->fl_type = req->a_res.lock.fl.fl_type;
  			fl->fl_pid = 0;
  			break;
  		default:
  			status = nlm_stat_to_errno(req->a_res.status);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
441
  	}
92737230d   Trond Myklebust   NLM: Add nlmclnt_...
442
443
444
  out:
  	nlm_release_call(req);
  	return status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
445
446
447
448
  }
  
  static void nlmclnt_locks_copy_lock(struct file_lock *new, struct file_lock *fl)
  {
4c060b531   Trond Myklebust   lockd: Fix Oopses...
449
450
451
  	new->fl_u.nfs_fl.state = fl->fl_u.nfs_fl.state;
  	new->fl_u.nfs_fl.owner = nlm_get_lockowner(fl->fl_u.nfs_fl.owner);
  	list_add_tail(&new->fl_u.nfs_fl.list, &fl->fl_u.nfs_fl.owner->host->h_granted);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
452
453
454
455
  }
  
  static void nlmclnt_locks_release_private(struct file_lock *fl)
  {
4c060b531   Trond Myklebust   lockd: Fix Oopses...
456
  	list_del(&fl->fl_u.nfs_fl.list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
457
  	nlm_put_lockowner(fl->fl_u.nfs_fl.owner);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
458
  }
6aed62853   Alexey Dobriyan   const: make file_...
459
  static const struct file_lock_operations nlmclnt_lock_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
460
461
462
463
464
465
466
467
  	.fl_copy_lock = nlmclnt_locks_copy_lock,
  	.fl_release_private = nlmclnt_locks_release_private,
  };
  
  static void nlmclnt_locks_init_private(struct file_lock *fl, struct nlm_host *host)
  {
  	BUG_ON(fl->fl_ops != NULL);
  	fl->fl_u.nfs_fl.state = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
468
  	fl->fl_u.nfs_fl.owner = nlm_find_lockowner(host, fl->fl_owner);
4c060b531   Trond Myklebust   lockd: Fix Oopses...
469
  	INIT_LIST_HEAD(&fl->fl_u.nfs_fl.list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
470
471
  	fl->fl_ops = &nlmclnt_lock_ops;
  }
9b0735749   Trond Myklebust   NLM,NFSv4: Don't ...
472
  static int do_vfs_lock(struct file_lock *fl)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
473
474
475
476
477
478
479
480
481
482
483
484
  {
  	int res = 0;
  	switch (fl->fl_flags & (FL_POSIX|FL_FLOCK)) {
  		case FL_POSIX:
  			res = posix_lock_file_wait(fl->fl_file, fl);
  			break;
  		case FL_FLOCK:
  			res = flock_lock_file_wait(fl->fl_file, fl);
  			break;
  		default:
  			BUG();
  	}
9b0735749   Trond Myklebust   NLM,NFSv4: Don't ...
485
  	return res;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
  }
  
  /*
   * LOCK: Try to create a lock
   *
   *			Programmer Harassment Alert
   *
   * When given a blocking lock request in a sync RPC call, the HPUX lockd
   * will faithfully return LCK_BLOCKED but never cares to notify us when
   * the lock could be granted. This way, our local process could hang
   * around forever waiting for the callback.
   *
   *  Solution A:	Implement busy-waiting
   *  Solution B: Use the async version of the call (NLM_LOCK_{MSG,RES})
   *
   * For now I am implementing solution A, because I hate the idea of
   * re-implementing lockd for a third time in two months. The async
   * calls shouldn't be too hard to do, however.
   *
   * This is one of the lovely things about standards in the NFS area:
   * they're so soft and squishy you can't really blame HP for doing this.
   */
  static int
  nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl)
  {
d11d10cc0   Trond Myklebust   NLM/lockd: Ensure...
511
  	struct rpc_cred *cred = nfs_file_cred(fl->fl_file);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
512
513
  	struct nlm_host	*host = req->a_host;
  	struct nlm_res	*resp = &req->a_res;
3a649b884   Trond Myklebust   NLM: Simplify cli...
514
  	struct nlm_wait *block = NULL;
01c3b861c   Trond Myklebust   NLM,NFSv4: Wait o...
515
  	unsigned char fl_flags = fl->fl_flags;
5f50c0c6d   Trond Myklebust   NLM/lockd: Fix a ...
516
  	unsigned char fl_type;
3a649b884   Trond Myklebust   NLM: Simplify cli...
517
  	int status = -ENOLCK;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
518

501c1ed3f   Chuck Lever   NLM: Remove redun...
519
  	if (nsm_monitor(host) < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
520
  		goto out;
6c9dc4255   Chuck Lever   lockd: Update NSM...
521
  	req->a_args.state = nsm_local_state;
501c1ed3f   Chuck Lever   NLM: Remove redun...
522

01c3b861c   Trond Myklebust   NLM,NFSv4: Wait o...
523
524
  	fl->fl_flags |= FL_ACCESS;
  	status = do_vfs_lock(fl);
4a9af59fe   Trond Myklebust   NLM/lockd: Ensure...
525
  	fl->fl_flags = fl_flags;
01c3b861c   Trond Myklebust   NLM,NFSv4: Wait o...
526
527
  	if (status < 0)
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
528

3a649b884   Trond Myklebust   NLM: Simplify cli...
529
  	block = nlmclnt_prepare_block(host, fl);
28df955a2   Trond Myklebust   NLM: Fix reclaim ...
530
  again:
5f50c0c6d   Trond Myklebust   NLM/lockd: Fix a ...
531
532
533
534
535
  	/*
  	 * Initialise resp->status to a valid non-zero value,
  	 * since 0 == nlm_lck_granted
  	 */
  	resp->status = nlm_lck_blocked;
ecdbf769b   Trond Myklebust   [PATCH] NLM: fix ...
536
  	for(;;) {
28df955a2   Trond Myklebust   NLM: Fix reclaim ...
537
538
  		/* Reboot protection */
  		fl->fl_u.nfs_fl.state = host->h_state;
d11d10cc0   Trond Myklebust   NLM/lockd: Ensure...
539
  		status = nlmclnt_call(cred, req, NLMPROC_LOCK);
ecdbf769b   Trond Myklebust   [PATCH] NLM: fix ...
540
  		if (status < 0)
ecdbf769b   Trond Myklebust   [PATCH] NLM: fix ...
541
  			break;
ecdbf769b   Trond Myklebust   [PATCH] NLM: fix ...
542
  		/* Did a reclaimer thread notify us of a server reboot? */
e8c5c045d   Al Viro   [PATCH] lockd end...
543
  		if (resp->status ==  nlm_lck_denied_grace_period)
ecdbf769b   Trond Myklebust   [PATCH] NLM: fix ...
544
  			continue;
e8c5c045d   Al Viro   [PATCH] lockd end...
545
  		if (resp->status != nlm_lck_blocked)
ecdbf769b   Trond Myklebust   [PATCH] NLM: fix ...
546
  			break;
3a649b884   Trond Myklebust   NLM: Simplify cli...
547
548
  		/* Wait on an NLM blocking lock */
  		status = nlmclnt_block(block, req, NLMCLNT_POLL_TIMEOUT);
3a649b884   Trond Myklebust   NLM: Simplify cli...
549
  		if (status < 0)
5f50c0c6d   Trond Myklebust   NLM/lockd: Fix a ...
550
  			break;
e8c5c045d   Al Viro   [PATCH] lockd end...
551
  		if (resp->status != nlm_lck_blocked)
3a649b884   Trond Myklebust   NLM: Simplify cli...
552
  			break;
ecdbf769b   Trond Myklebust   [PATCH] NLM: fix ...
553
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
554

5f50c0c6d   Trond Myklebust   NLM/lockd: Fix a ...
555
556
557
558
559
560
561
562
563
  	/* if we were interrupted while blocking, then cancel the lock request
  	 * and exit
  	 */
  	if (resp->status == nlm_lck_blocked) {
  		if (!req->a_args.block)
  			goto out_unlock;
  		if (nlmclnt_cancel(host, req->a_args.block, fl) == 0)
  			goto out_unblock;
  	}
e8c5c045d   Al Viro   [PATCH] lockd end...
564
  	if (resp->status == nlm_granted) {
28df955a2   Trond Myklebust   NLM: Fix reclaim ...
565
566
567
568
569
570
  		down_read(&host->h_rwsem);
  		/* Check whether or not the server has rebooted */
  		if (fl->fl_u.nfs_fl.state != host->h_state) {
  			up_read(&host->h_rwsem);
  			goto again;
  		}
4c060b531   Trond Myklebust   lockd: Fix Oopses...
571
  		/* Ensure the resulting lock will get added to granted list */
4a9af59fe   Trond Myklebust   NLM/lockd: Ensure...
572
  		fl->fl_flags |= FL_SLEEP;
9b0735749   Trond Myklebust   NLM,NFSv4: Don't ...
573
  		if (do_vfs_lock(fl) < 0)
8e24eea72   Harvey Harrison   fs: replace remai...
574
575
  			printk(KERN_WARNING "%s: VFS is out of sync with lock manager!
  ", __func__);
28df955a2   Trond Myklebust   NLM: Fix reclaim ...
576
  		up_read(&host->h_rwsem);
4a9af59fe   Trond Myklebust   NLM/lockd: Ensure...
577
  		fl->fl_flags = fl_flags;
5f50c0c6d   Trond Myklebust   NLM/lockd: Fix a ...
578
  		status = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
579
  	}
5f50c0c6d   Trond Myklebust   NLM/lockd: Fix a ...
580
581
  	if (status < 0)
  		goto out_unlock;
cc77b1521   Miklos Szeredi   lockd: dont retur...
582
583
584
585
586
587
588
589
590
  	/*
  	 * EAGAIN doesn't make sense for sleeping locks, and in some
  	 * cases NLM_LCK_DENIED is returned for a permanent error.  So
  	 * turn it into an ENOLCK.
  	 */
  	if (resp->status == nlm_lck_denied && (fl_flags & FL_SLEEP))
  		status = -ENOLCK;
  	else
  		status = nlm_stat_to_errno(resp->status);
ecdbf769b   Trond Myklebust   [PATCH] NLM: fix ...
591
  out_unblock:
3a649b884   Trond Myklebust   NLM: Simplify cli...
592
  	nlmclnt_finish_block(block);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
593
  out:
92737230d   Trond Myklebust   NLM: Add nlmclnt_...
594
  	nlm_release_call(req);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
595
  	return status;
5f50c0c6d   Trond Myklebust   NLM/lockd: Fix a ...
596
597
598
599
600
601
602
603
604
605
606
607
608
609
  out_unlock:
  	/* Fatal error: ensure that we remove the lock altogether */
  	dprintk("lockd: lock attempt ended in fatal error.
  "
  		"       Attempting to unlock.
  ");
  	nlmclnt_finish_block(block);
  	fl_type = fl->fl_type;
  	fl->fl_type = F_UNLCK;
  	down_read(&host->h_rwsem);
  	do_vfs_lock(fl);
  	up_read(&host->h_rwsem);
  	fl->fl_type = fl_type;
  	fl->fl_flags = fl_flags;
d11d10cc0   Trond Myklebust   NLM/lockd: Ensure...
610
  	nlmclnt_async_call(cred, req, NLMPROC_UNLOCK, &nlmclnt_unlock_ops);
5f50c0c6d   Trond Myklebust   NLM/lockd: Fix a ...
611
  	return status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
  }
  
  /*
   * RECLAIM: Try to reclaim a lock
   */
  int
  nlmclnt_reclaim(struct nlm_host *host, struct file_lock *fl)
  {
  	struct nlm_rqst reqst, *req;
  	int		status;
  
  	req = &reqst;
  	memset(req, 0, sizeof(*req));
  	locks_init_lock(&req->a_args.lock.fl);
  	locks_init_lock(&req->a_res.lock.fl);
  	req->a_host  = host;
  	req->a_flags = 0;
  
  	/* Set up the argument struct */
  	nlmclnt_setlockargs(req, fl);
  	req->a_args.reclaim = 1;
d11d10cc0   Trond Myklebust   NLM/lockd: Ensure...
633
634
  	status = nlmclnt_call(nfs_file_cred(fl->fl_file), req, NLMPROC_LOCK);
  	if (status >= 0 && req->a_res.status == nlm_granted)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
635
636
637
638
639
  		return 0;
  
  	printk(KERN_WARNING "lockd: failed to reclaim lock for pid %d "
  				"(errno %d, status %d)
  ", fl->fl_pid,
e8c5c045d   Al Viro   [PATCH] lockd end...
640
  				status, ntohl(req->a_res.status));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
  
  	/*
  	 * FIXME: This is a serious failure. We can
  	 *
  	 *  a.	Ignore the problem
  	 *  b.	Send the owning process some signal (Linux doesn't have
  	 *	SIGLOST, though...)
  	 *  c.	Retry the operation
  	 *
  	 * Until someone comes up with a simple implementation
  	 * for b or c, I'll choose option a.
  	 */
  
  	return -ENOLCK;
  }
  
  /*
   * UNLOCK: remove an existing lock
   */
  static int
  nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl)
  {
28df955a2   Trond Myklebust   NLM: Fix reclaim ...
663
  	struct nlm_host	*host = req->a_host;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
664
  	struct nlm_res	*resp = &req->a_res;
4a9af59fe   Trond Myklebust   NLM/lockd: Ensure...
665
666
  	int status;
  	unsigned char fl_flags = fl->fl_flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
667

26bcbf965   Christoph Hellwig   lockd: stop abusi...
668
  	/*
30f4e20a0   Trond Myklebust   [PATCH] NLM: Ensu...
669
670
671
672
  	 * Note: the server is supposed to either grant us the unlock
  	 * request, or to deny it with NLM_LCK_DENIED_GRACE_PERIOD. In either
  	 * case, we want to unlock.
  	 */
9b0735749   Trond Myklebust   NLM,NFSv4: Don't ...
673
  	fl->fl_flags |= FL_EXISTS;
28df955a2   Trond Myklebust   NLM: Fix reclaim ...
674
  	down_read(&host->h_rwsem);
4a9af59fe   Trond Myklebust   NLM/lockd: Ensure...
675
676
677
678
679
  	status = do_vfs_lock(fl);
  	up_read(&host->h_rwsem);
  	fl->fl_flags = fl_flags;
  	if (status == -ENOENT) {
  		status = 0;
9b0735749   Trond Myklebust   NLM,NFSv4: Don't ...
680
681
  		goto out;
  	}
30f4e20a0   Trond Myklebust   [PATCH] NLM: Ensu...
682

dc9d8d048   Trond Myklebust   NLM/lockd: conver...
683
  	atomic_inc(&req->a_count);
d11d10cc0   Trond Myklebust   NLM/lockd: Ensure...
684
685
  	status = nlmclnt_async_call(nfs_file_cred(fl->fl_file), req,
  			NLMPROC_UNLOCK, &nlmclnt_unlock_ops);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
686
  	if (status < 0)
92737230d   Trond Myklebust   NLM: Add nlmclnt_...
687
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
688

e8c5c045d   Al Viro   [PATCH] lockd end...
689
  	if (resp->status == nlm_granted)
92737230d   Trond Myklebust   NLM: Add nlmclnt_...
690
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
691

e8c5c045d   Al Viro   [PATCH] lockd end...
692
  	if (resp->status != nlm_lck_denied_nolocks)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
693
694
  		printk("lockd: unexpected unlock status: %d
  ", resp->status);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
695
  	/* What to do now? I'm out of my depth... */
92737230d   Trond Myklebust   NLM: Add nlmclnt_...
696
697
698
699
  	status = -ENOLCK;
  out:
  	nlm_release_call(req);
  	return status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
700
  }
963d8fe53   Trond Myklebust   RPC: Clean up RPC...
701
  static void nlmclnt_unlock_callback(struct rpc_task *task, void *data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
702
  {
963d8fe53   Trond Myklebust   RPC: Clean up RPC...
703
  	struct nlm_rqst	*req = data;
e8c5c045d   Al Viro   [PATCH] lockd end...
704
  	u32 status = ntohl(req->a_res.status);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
  
  	if (RPC_ASSASSINATED(task))
  		goto die;
  
  	if (task->tk_status < 0) {
  		dprintk("lockd: unlock failed (err = %d)
  ", -task->tk_status);
  		goto retry_rebind;
  	}
  	if (status == NLM_LCK_DENIED_GRACE_PERIOD) {
  		rpc_delay(task, NLMCLNT_GRACE_WAIT);
  		goto retry_unlock;
  	}
  	if (status != NLM_LCK_GRANTED)
  		printk(KERN_WARNING "lockd: unexpected unlock status: %d
  ", status);
  die:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
722
723
  	return;
   retry_rebind:
a86dc496b   Trond Myklebust   SUNRPC: Remove th...
724
  	lock_kernel();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
725
  	nlm_rebind_host(req->a_host);
a86dc496b   Trond Myklebust   SUNRPC: Remove th...
726
  	unlock_kernel();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
727
728
729
   retry_unlock:
  	rpc_restart_call(task);
  }
963d8fe53   Trond Myklebust   RPC: Clean up RPC...
730
731
  static const struct rpc_call_ops nlmclnt_unlock_ops = {
  	.rpc_call_done = nlmclnt_unlock_callback,
92737230d   Trond Myklebust   NLM: Add nlmclnt_...
732
  	.rpc_release = nlmclnt_rpc_release,
963d8fe53   Trond Myklebust   RPC: Clean up RPC...
733
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
734
735
736
737
738
  /*
   * Cancel a blocked lock request.
   * We always use an async RPC call for this in order not to hang a
   * process that has been Ctrl-C'ed.
   */
16fb24252   Trond Myklebust   NLM: Fix argument...
739
  static int nlmclnt_cancel(struct nlm_host *host, int block, struct file_lock *fl)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
740
741
  {
  	struct nlm_rqst	*req;
6b4b3a752   Trond Myklebust   NLM/lockd: Ensure...
742
743
744
745
746
747
  	int status;
  
  	dprintk("lockd: blocking lock attempt was interrupted by a signal.
  "
  		"       Attempting to cancel lock.
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
748

92737230d   Trond Myklebust   NLM: Add nlmclnt_...
749
  	req = nlm_alloc_call(nlm_get_host(host));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
750
751
  	if (!req)
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
752
753
754
  	req->a_flags = RPC_TASK_ASYNC;
  
  	nlmclnt_setlockargs(req, fl);
16fb24252   Trond Myklebust   NLM: Fix argument...
755
  	req->a_args.block = block;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
756

6b4b3a752   Trond Myklebust   NLM/lockd: Ensure...
757
  	atomic_inc(&req->a_count);
d11d10cc0   Trond Myklebust   NLM/lockd: Ensure...
758
759
  	status = nlmclnt_async_call(nfs_file_cred(fl->fl_file), req,
  			NLMPROC_CANCEL, &nlmclnt_cancel_ops);
6b4b3a752   Trond Myklebust   NLM/lockd: Ensure...
760
761
762
763
  	if (status == 0 && req->a_res.status == nlm_lck_denied)
  		status = -ENOLCK;
  	nlm_release_call(req);
  	return status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
764
  }
963d8fe53   Trond Myklebust   RPC: Clean up RPC...
765
  static void nlmclnt_cancel_callback(struct rpc_task *task, void *data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
766
  {
963d8fe53   Trond Myklebust   RPC: Clean up RPC...
767
  	struct nlm_rqst	*req = data;
e8c5c045d   Al Viro   [PATCH] lockd end...
768
  	u32 status = ntohl(req->a_res.status);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
769
770
771
772
773
774
775
776
777
778
  
  	if (RPC_ASSASSINATED(task))
  		goto die;
  
  	if (task->tk_status < 0) {
  		dprintk("lockd: CANCEL call error %d, retrying.
  ",
  					task->tk_status);
  		goto retry_cancel;
  	}
c041b5ff8   Chuck Lever   NLM: fix print fo...
779
780
  	dprintk("lockd: cancel status %u (task %u)
  ",
e8c5c045d   Al Viro   [PATCH] lockd end...
781
  			status, task->tk_pid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
782

e8c5c045d   Al Viro   [PATCH] lockd end...
783
  	switch (status) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
784
785
  	case NLM_LCK_GRANTED:
  	case NLM_LCK_DENIED_GRACE_PERIOD:
35576cba5   Trond Myklebust   NLM: nlmclnt_canc...
786
  	case NLM_LCK_DENIED:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
787
788
789
790
791
792
793
794
795
  		/* Everything's good */
  		break;
  	case NLM_LCK_DENIED_NOLOCKS:
  		dprintk("lockd: CANCEL failed (server has no locks)
  ");
  		goto retry_cancel;
  	default:
  		printk(KERN_NOTICE "lockd: weird return %d for CANCEL call
  ",
e8c5c045d   Al Viro   [PATCH] lockd end...
796
  			status);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
797
798
799
  	}
  
  die:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
800
801
802
  	return;
  
  retry_cancel:
aaaa99423   Trond Myklebust   NLM: Ensure that ...
803
804
805
  	/* Don't ever retry more than 3 times */
  	if (req->a_retries++ >= NLMCLNT_MAX_RETRIES)
  		goto die;
a86dc496b   Trond Myklebust   SUNRPC: Remove th...
806
  	lock_kernel();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
807
  	nlm_rebind_host(req->a_host);
a86dc496b   Trond Myklebust   SUNRPC: Remove th...
808
  	unlock_kernel();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
809
810
811
  	rpc_restart_call(task);
  	rpc_delay(task, 30 * HZ);
  }
963d8fe53   Trond Myklebust   RPC: Clean up RPC...
812
813
  static const struct rpc_call_ops nlmclnt_cancel_ops = {
  	.rpc_call_done = nlmclnt_cancel_callback,
92737230d   Trond Myklebust   NLM: Add nlmclnt_...
814
  	.rpc_release = nlmclnt_rpc_release,
963d8fe53   Trond Myklebust   RPC: Clean up RPC...
815
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
816
817
818
819
  /*
   * Convert an NLM status code to a generic kernel errno
   */
  static int
e8c5c045d   Al Viro   [PATCH] lockd end...
820
  nlm_stat_to_errno(__be32 status)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
821
  {
e8c5c045d   Al Viro   [PATCH] lockd end...
822
  	switch(ntohl(status)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
  	case NLM_LCK_GRANTED:
  		return 0;
  	case NLM_LCK_DENIED:
  		return -EAGAIN;
  	case NLM_LCK_DENIED_NOLOCKS:
  	case NLM_LCK_DENIED_GRACE_PERIOD:
  		return -ENOLCK;
  	case NLM_LCK_BLOCKED:
  		printk(KERN_NOTICE "lockd: unexpected status NLM_BLOCKED
  ");
  		return -ENOLCK;
  #ifdef CONFIG_LOCKD_V4
  	case NLM_DEADLCK:
  		return -EDEADLK;
  	case NLM_ROFS:
  		return -EROFS;
  	case NLM_STALE_FH:
  		return -ESTALE;
  	case NLM_FBIG:
  		return -EOVERFLOW;
  	case NLM_FAILED:
  		return -ENOLCK;
  #endif
  	}
  	printk(KERN_NOTICE "lockd: unexpected server status %d
  ", status);
  	return -ENOLCK;
  }