svclock.c 25.1 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
/*
 * linux/fs/lockd/svclock.c
 *
 * Handling of server-side locks, mostly of the blocked variety.
 * This is the ugliest part of lockd because we tread on very thin ice.
 * GRANT and CANCEL calls may get stuck, meet in mid-flight, etc.
 * IMNSHO introducing the grant callback into the NLM protocol was one
 * of the worst ideas Sun ever had. Except maybe for the idea of doing
 * NFS file locking at all.
 *
 * I'm trying hard to avoid race conditions by protecting most accesses
 * to a file's list of blocked locks through a semaphore. The global
 * list of blocked locks is not protected in this fashion however.
 * Therefore, some functions (such as the RPC callback for the async grant
 * call) move blocked locks towards the head of the list *while some other
 * process might be traversing it*. This should not be a problem in
 * practice, because this will only cause functions traversing the list
 * to visit some blocks twice.
 *
 * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
 */

#include <linux/types.h>
24
#include <linux/slab.h>
Linus Torvalds's avatar
Linus Torvalds committed
25 26 27 28
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/sunrpc/clnt.h>
29
#include <linux/sunrpc/svc_xprt.h>
Linus Torvalds's avatar
Linus Torvalds committed
30 31
#include <linux/lockd/nlm.h>
#include <linux/lockd/lockd.h>
32
#include <linux/kthread.h>
Linus Torvalds's avatar
Linus Torvalds committed
33 34 35 36 37 38 39 40 41

#define NLMDBG_FACILITY		NLMDBG_SVCLOCK

#ifdef CONFIG_LOCKD_V4
#define nlm_deadlock	nlm4_deadlock
#else
#define nlm_deadlock	nlm_lck_denied
#endif

42
static void nlmsvc_release_block(struct nlm_block *block);
Linus Torvalds's avatar
Linus Torvalds committed
43
static void	nlmsvc_insert_block(struct nlm_block *block, unsigned long);
44
static void	nlmsvc_remove_block(struct nlm_block *block);
45

46 47
static int nlmsvc_setgrantargs(struct nlm_rqst *call, struct nlm_lock *lock);
static void nlmsvc_freegrantargs(struct nlm_rqst *call);
48
static const struct rpc_call_ops nlmsvc_grant_ops;
Linus Torvalds's avatar
Linus Torvalds committed
49 50 51 52

/*
 * The list of blocked locks to retry
 */
53
static LIST_HEAD(nlm_blocked);
54
static DEFINE_SPINLOCK(nlm_blocked_lock);
Linus Torvalds's avatar
Linus Torvalds committed
55

Jeff Layton's avatar
Jeff Layton committed
56
#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
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
static const char *nlmdbg_cookie2a(const struct nlm_cookie *cookie)
{
	/*
	 * We can get away with a static buffer because we're only
	 * called with BKL held.
	 */
	static char buf[2*NLM_MAXCOOKIELEN+1];
	unsigned int i, len = sizeof(buf);
	char *p = buf;

	len--;	/* allow for trailing \0 */
	if (len < 3)
		return "???";
	for (i = 0 ; i < cookie->len ; i++) {
		if (len < 2) {
			strcpy(p-3, "...");
			break;
		}
		sprintf(p, "%02x", cookie->data[i]);
		p += 2;
		len -= 2;
	}
	*p = '\0';

	return buf;
}
#endif

Linus Torvalds's avatar
Linus Torvalds committed
85 86 87 88
/*
 * Insert a blocked lock into the global list
 */
static void
89
nlmsvc_insert_block_locked(struct nlm_block *block, unsigned long when)
Linus Torvalds's avatar
Linus Torvalds committed
90
{
91 92
	struct nlm_block *b;
	struct list_head *pos;
Linus Torvalds's avatar
Linus Torvalds committed
93 94

	dprintk("lockd: nlmsvc_insert_block(%p, %ld)\n", block, when);
95 96 97 98 99 100 101
	if (list_empty(&block->b_list)) {
		kref_get(&block->b_count);
	} else {
		list_del_init(&block->b_list);
	}

	pos = &nlm_blocked;
Linus Torvalds's avatar
Linus Torvalds committed
102 103 104
	if (when != NLM_NEVER) {
		if ((when += jiffies) == NLM_NEVER)
			when ++;
105 106 107 108 109 110 111 112 113
		list_for_each(pos, &nlm_blocked) {
			b = list_entry(pos, struct nlm_block, b_list);
			if (time_after(b->b_when,when) || b->b_when == NLM_NEVER)
				break;
		}
		/* On normal exit from the loop, pos == &nlm_blocked,
		 * so we will be adding to the end of the list - good
		 */
	}
Linus Torvalds's avatar
Linus Torvalds committed
114

115
	list_add_tail(&block->b_list, pos);
Linus Torvalds's avatar
Linus Torvalds committed
116 117 118
	block->b_when = when;
}

119 120 121 122 123 124 125
static void nlmsvc_insert_block(struct nlm_block *block, unsigned long when)
{
	spin_lock(&nlm_blocked_lock);
	nlmsvc_insert_block_locked(block, when);
	spin_unlock(&nlm_blocked_lock);
}

Linus Torvalds's avatar
Linus Torvalds committed
126 127 128
/*
 * Remove a block from the global list
 */
129
static inline void
Linus Torvalds's avatar
Linus Torvalds committed
130 131
nlmsvc_remove_block(struct nlm_block *block)
{
132
	if (!list_empty(&block->b_list)) {
133
		spin_lock(&nlm_blocked_lock);
134
		list_del_init(&block->b_list);
135
		spin_unlock(&nlm_blocked_lock);
136
		nlmsvc_release_block(block);
Linus Torvalds's avatar
Linus Torvalds committed
137 138 139 140
	}
}

/*
141
 * Find a block for a given lock
Linus Torvalds's avatar
Linus Torvalds committed
142 143
 */
static struct nlm_block *
144
nlmsvc_lookup_block(struct nlm_file *file, struct nlm_lock *lock)
Linus Torvalds's avatar
Linus Torvalds committed
145
{
146
	struct nlm_block	*block;
Linus Torvalds's avatar
Linus Torvalds committed
147 148 149 150 151 152
	struct file_lock	*fl;

	dprintk("lockd: nlmsvc_lookup_block f=%p pd=%d %Ld-%Ld ty=%d\n",
				file, lock->fl.fl_pid,
				(long long)lock->fl.fl_start,
				(long long)lock->fl.fl_end, lock->fl.fl_type);
153
	list_for_each_entry(block, &nlm_blocked, b_list) {
154
		fl = &block->b_call->a_args.lock.fl;
Linus Torvalds's avatar
Linus Torvalds committed
155 156 157 158
		dprintk("lockd: check f=%p pd=%d %Ld-%Ld ty=%d cookie=%s\n",
				block->b_file, fl->fl_pid,
				(long long)fl->fl_start,
				(long long)fl->fl_end, fl->fl_type,
159
				nlmdbg_cookie2a(&block->b_call->a_args.cookie));
Linus Torvalds's avatar
Linus Torvalds committed
160
		if (block->b_file == file && nlm_compare_locks(fl, &lock->fl)) {
161
			kref_get(&block->b_count);
Linus Torvalds's avatar
Linus Torvalds committed
162 163 164 165 166 167 168 169 170
			return block;
		}
	}

	return NULL;
}

static inline int nlm_cookie_match(struct nlm_cookie *a, struct nlm_cookie *b)
{
171
	if (a->len != b->len)
Linus Torvalds's avatar
Linus Torvalds committed
172
		return 0;
173
	if (memcmp(a->data, b->data, a->len))
Linus Torvalds's avatar
Linus Torvalds committed
174 175 176 177 178 179 180 181
		return 0;
	return 1;
}

/*
 * Find a block with a given NLM cookie.
 */
static inline struct nlm_block *
182
nlmsvc_find_block(struct nlm_cookie *cookie)
Linus Torvalds's avatar
Linus Torvalds committed
183 184 185
{
	struct nlm_block *block;

186
	list_for_each_entry(block, &nlm_blocked, b_list) {
187
		if (nlm_cookie_match(&block->b_call->a_args.cookie,cookie))
188
			goto found;
Linus Torvalds's avatar
Linus Torvalds committed
189 190
	}

191 192 193
	return NULL;

found:
194
	dprintk("nlmsvc_find_block(%s): block=%p\n", nlmdbg_cookie2a(cookie), block);
195
	kref_get(&block->b_count);
Linus Torvalds's avatar
Linus Torvalds committed
196 197 198 199 200 201 202 203 204 205 206 207
	return block;
}

/*
 * Create a block and initialize it.
 *
 * Note: we explicitly set the cookie of the grant reply to that of
 * the blocked lock request. The spec explicitly mentions that the client
 * should _not_ rely on the callback containing the same cookie as the
 * request, but (as I found out later) that's because some implementations
 * do just this. Never mind the standards comittees, they support our
 * logging industries.
208 209 210 211 212
 *
 * 10 years later: I hope we can safely ignore these old and broken
 * clients by now. Let's fix this so we can uniquely identify an incoming
 * GRANTED_RES message by cookie, without having to rely on the client's IP
 * address. --okir
Linus Torvalds's avatar
Linus Torvalds committed
213
 */
214 215 216 217
static struct nlm_block *
nlmsvc_create_block(struct svc_rqst *rqstp, struct nlm_host *host,
		    struct nlm_file *file, struct nlm_lock *lock,
		    struct nlm_cookie *cookie)
Linus Torvalds's avatar
Linus Torvalds committed
218 219
{
	struct nlm_block	*block;
220
	struct nlm_rqst		*call = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
221

222 223 224 225
	call = nlm_alloc_call(host);
	if (call == NULL)
		return NULL;

Linus Torvalds's avatar
Linus Torvalds committed
226
	/* Allocate memory for block, and initialize arguments */
227 228
	block = kzalloc(sizeof(*block), GFP_KERNEL);
	if (block == NULL)
Linus Torvalds's avatar
Linus Torvalds committed
229
		goto failed;
230
	kref_init(&block->b_count);
231 232
	INIT_LIST_HEAD(&block->b_list);
	INIT_LIST_HEAD(&block->b_flist);
Linus Torvalds's avatar
Linus Torvalds committed
233

234
	if (!nlmsvc_setgrantargs(call, lock))
Linus Torvalds's avatar
Linus Torvalds committed
235 236 237
		goto failed_free;

	/* Set notifier function for VFS, and init args */
238 239
	call->a_args.lock.fl.fl_flags |= FL_SLEEP;
	call->a_args.lock.fl.fl_lmops = &nlmsvc_lock_operations;
240
	nlmclnt_next_cookie(&call->a_args.cookie);
Linus Torvalds's avatar
Linus Torvalds committed
241 242 243 244 245 246 247

	dprintk("lockd: created block %p...\n", block);

	/* Create and initialize the block */
	block->b_daemon = rqstp->rq_server;
	block->b_host   = host;
	block->b_file   = file;
248
	file->f_count++;
Linus Torvalds's avatar
Linus Torvalds committed
249 250

	/* Add to file's list of blocks */
251
	list_add(&block->b_flist, &file->f_blocks);
Linus Torvalds's avatar
Linus Torvalds committed
252 253

	/* Set up RPC arguments for callback */
254
	block->b_call = call;
Linus Torvalds's avatar
Linus Torvalds committed
255
	call->a_flags   = RPC_TASK_ASYNC;
256
	call->a_block = block;
Linus Torvalds's avatar
Linus Torvalds committed
257 258 259 260 261 262

	return block;

failed_free:
	kfree(block);
failed:
Chuck Lever's avatar
Chuck Lever committed
263
	nlmsvc_release_call(call);
Linus Torvalds's avatar
Linus Torvalds committed
264 265 266 267
	return NULL;
}

/*
268
 * Delete a block.
Linus Torvalds's avatar
Linus Torvalds committed
269 270 271
 * It is the caller's responsibility to check whether the file
 * can be closed hereafter.
 */
272
static int nlmsvc_unlink_block(struct nlm_block *block)
Linus Torvalds's avatar
Linus Torvalds committed
273
{
274
	int status;
275
	dprintk("lockd: unlinking block %p...\n", block);
Linus Torvalds's avatar
Linus Torvalds committed
276 277

	/* Remove block from list */
278
	status = posix_unblock_lock(&block->b_call->a_args.lock.fl);
Linus Torvalds's avatar
Linus Torvalds committed
279
	nlmsvc_remove_block(block);
280 281
	return status;
}
Linus Torvalds's avatar
Linus Torvalds committed
282

283 284 285 286 287 288
static void nlmsvc_free_block(struct kref *kref)
{
	struct nlm_block *block = container_of(kref, struct nlm_block, b_count);
	struct nlm_file		*file = block->b_file;

	dprintk("lockd: freeing block %p...\n", block);
Linus Torvalds's avatar
Linus Torvalds committed
289 290

	/* Remove block from file's list of blocks */
291
	list_del_init(&block->b_flist);
292
	mutex_unlock(&file->f_mutex);
Linus Torvalds's avatar
Linus Torvalds committed
293

294
	nlmsvc_freegrantargs(block->b_call);
Chuck Lever's avatar
Chuck Lever committed
295
	nlmsvc_release_call(block->b_call);
296
	nlm_release_file(block->b_file);
Linus Torvalds's avatar
Linus Torvalds committed
297
	kfree(block);
298 299 300 301 302
}

static void nlmsvc_release_block(struct nlm_block *block)
{
	if (block != NULL)
303
		kref_put_mutex(&block->b_count, nlmsvc_free_block, &block->b_file->f_mutex);
Linus Torvalds's avatar
Linus Torvalds committed
304 305
}

306 307 308 309 310 311 312
/*
 * Loop over all blocks and delete blocks held by
 * a matching host.
 */
void nlmsvc_traverse_blocks(struct nlm_host *host,
			struct nlm_file *file,
			nlm_host_match_fn_t match)
313
{
314
	struct nlm_block *block, *next;
315 316

restart:
317
	mutex_lock(&file->f_mutex);
318
	list_for_each_entry_safe(block, next, &file->f_blocks, b_flist) {
319
		if (!match(block->b_host, host))
320
			continue;
321 322 323
		/* Do not destroy blocks that are not on
		 * the global retry list - why? */
		if (list_empty(&block->b_list))
324 325
			continue;
		kref_get(&block->b_count);
326
		mutex_unlock(&file->f_mutex);
327 328 329 330
		nlmsvc_unlink_block(block);
		nlmsvc_release_block(block);
		goto restart;
	}
331
	mutex_unlock(&file->f_mutex);
332 333
}

334 335 336 337 338 339 340 341
/*
 * Initialize arguments for GRANTED call. The nlm_rqst structure
 * has been cleared already.
 */
static int nlmsvc_setgrantargs(struct nlm_rqst *call, struct nlm_lock *lock)
{
	locks_copy_lock(&call->a_args.lock.fl, &lock->fl);
	memcpy(&call->a_args.lock.fh, &lock->fh, sizeof(call->a_args.lock.fh));
342
	call->a_args.lock.caller = utsname()->nodename;
343 344 345 346 347 348 349 350
	call->a_args.lock.oh.len = lock->oh.len;

	/* set default data area */
	call->a_args.lock.oh.data = call->a_owner;
	call->a_args.lock.svid = lock->fl.fl_pid;

	if (lock->oh.len > NLMCLNT_OHSIZE) {
		void *data = kmalloc(lock->oh.len, GFP_KERNEL);
351
		if (!data)
352 353 354 355 356 357 358 359 360 361
			return 0;
		call->a_args.lock.oh.data = (u8 *) data;
	}

	memcpy(call->a_args.lock.oh.data, lock->oh.data, lock->oh.len);
	return 1;
}

static void nlmsvc_freegrantargs(struct nlm_rqst *call)
{
362
	if (call->a_args.lock.oh.data != call->a_owner)
363
		kfree(call->a_args.lock.oh.data);
364 365

	locks_release_private(&call->a_args.lock.fl);
366 367
}

368 369 370
/*
 * Deferred lock request handling for non-blocking lock
 */
371
static __be32
372 373
nlmsvc_defer_lock_rqst(struct svc_rqst *rqstp, struct nlm_block *block)
{
374
	__be32 status = nlm_lck_denied_nolocks;
375 376 377 378 379 380 381 382 383 384 385 386 387

	block->b_flags |= B_QUEUED;

	nlmsvc_insert_block(block, NLM_TIMEOUT);

	block->b_cache_req = &rqstp->rq_chandle;
	if (rqstp->rq_chandle.defer) {
		block->b_deferred_req =
			rqstp->rq_chandle.defer(block->b_cache_req);
		if (block->b_deferred_req != NULL)
			status = nlm_drop_reply;
	}
	dprintk("lockd: nlmsvc_defer_lock_rqst block %p flags %d status %d\n",
388
		block, block->b_flags, ntohl(status));
389 390 391 392

	return status;
}

Linus Torvalds's avatar
Linus Torvalds committed
393 394 395 396
/*
 * Attempt to establish a lock, and if it can't be granted, block it
 * if required.
 */
Al Viro's avatar
Al Viro committed
397
__be32
Linus Torvalds's avatar
Linus Torvalds committed
398
nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file,
399
	    struct nlm_host *host, struct nlm_lock *lock, int wait,
400
	    struct nlm_cookie *cookie, int reclaim)
Linus Torvalds's avatar
Linus Torvalds committed
401
{
402
	struct nlm_block	*block = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
403
	int			error;
Al Viro's avatar
Al Viro committed
404
	__be32			ret;
Linus Torvalds's avatar
Linus Torvalds committed
405 406

	dprintk("lockd: nlmsvc_lock(%s/%ld, ty=%d, pi=%d, %Ld-%Ld, bl=%d)\n",
Al Viro's avatar
Al Viro committed
407 408
				file_inode(file->f_file)->i_sb->s_id,
				file_inode(file->f_file)->i_ino,
Linus Torvalds's avatar
Linus Torvalds committed
409 410 411 412 413 414
				lock->fl.fl_type, lock->fl.fl_pid,
				(long long)lock->fl.fl_start,
				(long long)lock->fl.fl_end,
				wait);

	/* Lock file against concurrent access */
415
	mutex_lock(&file->f_mutex);
416 417 418
	/* Get existing block (in case client is busy-waiting)
	 * or create new block
	 */
419
	block = nlmsvc_lookup_block(file, lock);
420
	if (block == NULL) {
421
		block = nlmsvc_create_block(rqstp, host, file, lock, cookie);
422 423 424
		ret = nlm_lck_denied_nolocks;
		if (block == NULL)
			goto out;
425
		lock = &block->b_call->a_args.lock;
426 427
	} else
		lock->fl.fl_flags &= ~FL_SLEEP;
Linus Torvalds's avatar
Linus Torvalds committed
428

429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444
	if (block->b_flags & B_QUEUED) {
		dprintk("lockd: nlmsvc_lock deferred block %p flags %d\n",
							block, block->b_flags);
		if (block->b_granted) {
			nlmsvc_unlink_block(block);
			ret = nlm_granted;
			goto out;
		}
		if (block->b_flags & B_TIMED_OUT) {
			nlmsvc_unlink_block(block);
			ret = nlm_lck_denied;
			goto out;
		}
		ret = nlm_drop_reply;
		goto out;
	}
Linus Torvalds's avatar
Linus Torvalds committed
445

446
	if (locks_in_grace(SVC_NET(rqstp)) && !reclaim) {
447 448 449
		ret = nlm_lck_denied_grace_period;
		goto out;
	}
450
	if (reclaim && !locks_in_grace(SVC_NET(rqstp))) {
451 452 453
		ret = nlm_lck_denied_grace_period;
		goto out;
	}
454

455 456 457 458
	if (!wait)
		lock->fl.fl_flags &= ~FL_SLEEP;
	error = vfs_lock_file(file->f_file, F_SETLK, &lock->fl, NULL);
	lock->fl.fl_flags &= ~FL_SLEEP;
459

460
	dprintk("lockd: vfs_lock_file returned %d\n", error);
461
	switch (error) {
Linus Torvalds's avatar
Linus Torvalds committed
462
		case 0:
Andy Adamson's avatar
Andy Adamson committed
463 464
			ret = nlm_granted;
			goto out;
465
		case -EAGAIN:
466 467 468 469 470 471 472
			/*
			 * If this is a blocking request for an
			 * already pending lock request then we need
			 * to put it back on lockd's block list
			 */
			if (wait)
				break;
473
			ret = nlm_lck_denied;
474
			goto out;
475
		case FILE_LOCK_DEFERRED:
476 477 478 479 480 481
			if (wait)
				break;
			/* Filesystem lock operation is in progress
			   Add it to the queue waiting for callback */
			ret = nlmsvc_defer_lock_rqst(rqstp, block);
			goto out;
482
		case -EDEADLK:
Andy Adamson's avatar
Andy Adamson committed
483 484
			ret = nlm_deadlock;
			goto out;
Linus Torvalds's avatar
Linus Torvalds committed
485
		default:			/* includes ENOLCK */
Andy Adamson's avatar
Andy Adamson committed
486 487
			ret = nlm_lck_denied_nolocks;
			goto out;
Linus Torvalds's avatar
Linus Torvalds committed
488 489
	}

490
	ret = nlm_lck_blocked;
Linus Torvalds's avatar
Linus Torvalds committed
491 492

	/* Append to list of blocked */
493
	nlmsvc_insert_block(block, NLM_NEVER);
Andy Adamson's avatar
Andy Adamson committed
494
out:
495
	mutex_unlock(&file->f_mutex);
496
	nlmsvc_release_block(block);
Andy Adamson's avatar
Andy Adamson committed
497 498
	dprintk("lockd: nlmsvc_lock returned %u\n", ret);
	return ret;
Linus Torvalds's avatar
Linus Torvalds committed
499 500 501 502 503
}

/*
 * Test for presence of a conflicting lock.
 */
Al Viro's avatar
Al Viro committed
504
__be32
505
nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file,
506 507
		struct nlm_host *host, struct nlm_lock *lock,
		struct nlm_lock *conflock, struct nlm_cookie *cookie)
Linus Torvalds's avatar
Linus Torvalds committed
508
{
Marc Eshel's avatar
Marc Eshel committed
509 510 511
	int			error;
	__be32			ret;

Linus Torvalds's avatar
Linus Torvalds committed
512
	dprintk("lockd: nlmsvc_testlock(%s/%ld, ty=%d, %Ld-%Ld)\n",
Al Viro's avatar
Al Viro committed
513 514
				file_inode(file->f_file)->i_sb->s_id,
				file_inode(file->f_file)->i_ino,
Linus Torvalds's avatar
Linus Torvalds committed
515 516 517 518
				lock->fl.fl_type,
				(long long)lock->fl.fl_start,
				(long long)lock->fl.fl_end);

519
	if (locks_in_grace(SVC_NET(rqstp))) {
520 521 522
		ret = nlm_lck_denied_grace_period;
		goto out;
	}
523

Marc Eshel's avatar
Marc Eshel committed
524 525
	error = vfs_test_lock(file->f_file, &lock->fl);
	if (error) {
526 527 528 529
		/* We can't currently deal with deferred test requests */
		if (error == FILE_LOCK_DEFERRED)
			WARN_ON_ONCE(1);

Marc Eshel's avatar
Marc Eshel committed
530 531 532
		ret = nlm_lck_denied_nolocks;
		goto out;
	}
533

Marc Eshel's avatar
Marc Eshel committed
534 535 536 537 538 539 540 541 542 543 544 545 546 547 548
	if (lock->fl.fl_type == F_UNLCK) {
		ret = nlm_granted;
		goto out;
	}

	dprintk("lockd: conflicting lock(ty=%d, %Ld-%Ld)\n",
		lock->fl.fl_type, (long long)lock->fl.fl_start,
		(long long)lock->fl.fl_end);
	conflock->caller = "somehost";	/* FIXME */
	conflock->len = strlen(conflock->caller);
	conflock->oh.len = 0;		/* don't return OH info */
	conflock->svid = lock->fl.fl_pid;
	conflock->fl.fl_type = lock->fl.fl_type;
	conflock->fl.fl_start = lock->fl.fl_start;
	conflock->fl.fl_end = lock->fl.fl_end;
549
	locks_release_private(&lock->fl);
Marc Eshel's avatar
Marc Eshel committed
550 551 552
	ret = nlm_lck_denied;
out:
	return ret;
Linus Torvalds's avatar
Linus Torvalds committed
553 554 555 556 557 558 559 560 561
}

/*
 * Remove a lock.
 * This implies a CANCEL call: We send a GRANT_MSG, the client replies
 * with a GRANT_RES call which gets lost, and calls UNLOCK immediately
 * afterwards. In this case the block will still be there, and hence
 * must be removed.
 */
Al Viro's avatar
Al Viro committed
562
__be32
563
nlmsvc_unlock(struct net *net, struct nlm_file *file, struct nlm_lock *lock)
Linus Torvalds's avatar
Linus Torvalds committed
564 565 566 567
{
	int	error;

	dprintk("lockd: nlmsvc_unlock(%s/%ld, pi=%d, %Ld-%Ld)\n",
Al Viro's avatar
Al Viro committed
568 569
				file_inode(file->f_file)->i_sb->s_id,
				file_inode(file->f_file)->i_ino,
Linus Torvalds's avatar
Linus Torvalds committed
570 571 572 573 574
				lock->fl.fl_pid,
				(long long)lock->fl.fl_start,
				(long long)lock->fl.fl_end);

	/* First, cancel any lock that might be there */
575
	nlmsvc_cancel_blocked(net, file, lock);
Linus Torvalds's avatar
Linus Torvalds committed
576 577

	lock->fl.fl_type = F_UNLCK;
578
	error = vfs_lock_file(file->f_file, F_SETLK, &lock->fl, NULL);
Linus Torvalds's avatar
Linus Torvalds committed
579 580 581 582 583 584 585 586 587 588 589

	return (error < 0)? nlm_lck_denied_nolocks : nlm_granted;
}

/*
 * Cancel a previously blocked request.
 *
 * A cancel request always overrides any grant that may currently
 * be in progress.
 * The calling procedure must check whether the file can be closed.
 */
Al Viro's avatar
Al Viro committed
590
__be32
591
nlmsvc_cancel_blocked(struct net *net, struct nlm_file *file, struct nlm_lock *lock)
Linus Torvalds's avatar
Linus Torvalds committed
592 593
{
	struct nlm_block	*block;
J. Bruce Fields's avatar
J. Bruce Fields committed
594
	int status = 0;
Linus Torvalds's avatar
Linus Torvalds committed
595 596

	dprintk("lockd: nlmsvc_cancel(%s/%ld, pi=%d, %Ld-%Ld)\n",
Al Viro's avatar
Al Viro committed
597 598
				file_inode(file->f_file)->i_sb->s_id,
				file_inode(file->f_file)->i_ino,
Linus Torvalds's avatar
Linus Torvalds committed
599 600 601 602
				lock->fl.fl_pid,
				(long long)lock->fl.fl_start,
				(long long)lock->fl.fl_end);

603
	if (locks_in_grace(net))
604 605
		return nlm_lck_denied_grace_period;

606
	mutex_lock(&file->f_mutex);
607
	block = nlmsvc_lookup_block(file, lock);
608
	mutex_unlock(&file->f_mutex);
609
	if (block != NULL) {
610 611
		vfs_cancel_lock(block->b_file->f_file,
				&block->b_call->a_args.lock.fl);
612 613 614
		status = nlmsvc_unlink_block(block);
		nlmsvc_release_block(block);
	}
J. Bruce Fields's avatar
J. Bruce Fields committed
615
	return status ? nlm_lck_denied : nlm_granted;
Linus Torvalds's avatar
Linus Torvalds committed
616 617
}

Marc Eshel's avatar
Marc Eshel committed
618 619
/*
 * This is a callback from the filesystem for VFS file lock requests.
620
 * It will be used if lm_grant is defined and the filesystem can not
Marc Eshel's avatar
Marc Eshel committed
621 622 623 624 625 626 627
 * respond to the request immediately.
 * For SETLK or SETLKW request it will get the local posix lock.
 * In all cases it will move the block to the head of nlm_blocked q where
 * nlmsvc_retry_blocked() can send back a reply for SETLKW or revisit the
 * deferred rpc for GETLK and SETLK.
 */
static void
628
nlmsvc_update_deferred_block(struct nlm_block *block, int result)
Marc Eshel's avatar
Marc Eshel committed
629 630 631 632 633 634 635 636
{
	block->b_flags |= B_GOT_CALLBACK;
	if (result == 0)
		block->b_granted = 1;
	else
		block->b_flags |= B_TIMED_OUT;
}

637
static int nlmsvc_grant_deferred(struct file_lock *fl, int result)
Marc Eshel's avatar
Marc Eshel committed
638 639 640 641
{
	struct nlm_block *block;
	int rc = -ENOENT;

642
	spin_lock(&nlm_blocked_lock);
Marc Eshel's avatar
Marc Eshel committed
643 644 645 646 647 648 649 650 651
	list_for_each_entry(block, &nlm_blocked, b_list) {
		if (nlm_compare_locks(&block->b_call->a_args.lock.fl, fl)) {
			dprintk("lockd: nlmsvc_notify_blocked block %p flags %d\n",
							block, block->b_flags);
			if (block->b_flags & B_QUEUED) {
				if (block->b_flags & B_TIMED_OUT) {
					rc = -ENOLCK;
					break;
				}
652
				nlmsvc_update_deferred_block(block, result);
Marc Eshel's avatar
Marc Eshel committed
653 654 655
			} else if (result == 0)
				block->b_granted = 1;

656
			nlmsvc_insert_block_locked(block, 0);
Marc Eshel's avatar
Marc Eshel committed
657 658 659 660 661
			svc_wake_up(block->b_daemon);
			rc = 0;
			break;
		}
	}
662
	spin_unlock(&nlm_blocked_lock);
Marc Eshel's avatar
Marc Eshel committed
663 664 665 666 667
	if (rc == -ENOENT)
		printk(KERN_WARNING "lockd: grant for unknown block\n");
	return rc;
}

Linus Torvalds's avatar
Linus Torvalds committed
668 669 670 671 672 673 674 675 676 677
/*
 * Unblock a blocked lock request. This is a callback invoked from the
 * VFS layer when a lock on which we blocked is removed.
 *
 * This function doesn't grant the blocked lock instantly, but rather moves
 * the block to the head of nlm_blocked where it can be picked up by lockd.
 */
static void
nlmsvc_notify_blocked(struct file_lock *fl)
{
678
	struct nlm_block	*block;
Linus Torvalds's avatar
Linus Torvalds committed
679 680

	dprintk("lockd: VFS unblock notification for block %p\n", fl);
681
	spin_lock(&nlm_blocked_lock);
682
	list_for_each_entry(block, &nlm_blocked, b_list) {
683
		if (nlm_compare_locks(&block->b_call->a_args.lock.fl, fl)) {
684 685
			nlmsvc_insert_block_locked(block, 0);
			spin_unlock(&nlm_blocked_lock);
Linus Torvalds's avatar
Linus Torvalds committed
686 687 688 689
			svc_wake_up(block->b_daemon);
			return;
		}
	}
690
	spin_unlock(&nlm_blocked_lock);
Linus Torvalds's avatar
Linus Torvalds committed
691 692 693 694 695 696 697 698
	printk(KERN_WARNING "lockd: notification for unknown block!\n");
}

static int nlmsvc_same_owner(struct file_lock *fl1, struct file_lock *fl2)
{
	return fl1->fl_owner == fl2->fl_owner && fl1->fl_pid == fl2->fl_pid;
}

699 700 701 702 703 704 705 706 707 708 709
/*
 * Since NLM uses two "keys" for tracking locks, we need to hash them down
 * to one for the blocked_hash. Here, we're just xor'ing the host address
 * with the pid in order to create a key value for picking a hash bucket.
 */
static unsigned long
nlmsvc_owner_key(struct file_lock *fl)
{
	return (unsigned long)fl->fl_owner ^ (unsigned long)fl->fl_pid;
}

710
const struct lock_manager_operations nlmsvc_lock_operations = {
711
	.lm_compare_owner = nlmsvc_same_owner,
712
	.lm_owner_key = nlmsvc_owner_key,
713 714
	.lm_notify = nlmsvc_notify_blocked,
	.lm_grant = nlmsvc_grant_deferred,
Linus Torvalds's avatar
Linus Torvalds committed
715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731
};

/*
 * Try to claim a lock that was previously blocked.
 *
 * Note that we use both the RPC_GRANTED_MSG call _and_ an async
 * RPC thread when notifying the client. This seems like overkill...
 * Here's why:
 *  -	we don't want to use a synchronous RPC thread, otherwise
 *	we might find ourselves hanging on a dead portmapper.
 *  -	Some lockd implementations (e.g. HP) don't react to
 *	RPC_GRANTED calls; they seem to insist on RPC_GRANTED_MSG calls.
 */
static void
nlmsvc_grant_blocked(struct nlm_block *block)
{
	struct nlm_file		*file = block->b_file;
732
	struct nlm_lock		*lock = &block->b_call->a_args.lock;
Linus Torvalds's avatar
Linus Torvalds committed
733
	int			error;
734
	loff_t			fl_start, fl_end;
Linus Torvalds's avatar
Linus Torvalds committed
735 736 737

	dprintk("lockd: grant blocked lock %p\n", block);

Marc Eshel's avatar
Marc Eshel committed
738 739
	kref_get(&block->b_count);

Linus Torvalds's avatar
Linus Torvalds committed
740
	/* Unlink block request from list */
741
	nlmsvc_unlink_block(block);
Linus Torvalds's avatar
Linus Torvalds committed
742 743 744 745 746 747 748 749 750 751

	/* If b_granted is true this means we've been here before.
	 * Just retry the grant callback, possibly refreshing the RPC
	 * binding */
	if (block->b_granted) {
		nlm_rebind_host(block->b_host);
		goto callback;
	}

	/* Try the lock operation again */
752 753 754
	/* vfs_lock_file() can mangle fl_start and fl_end, but we need
	 * them unchanged for the GRANT_MSG
	 */
755
	lock->fl.fl_flags |= FL_SLEEP;
756 757
	fl_start = lock->fl.fl_start;
	fl_end = lock->fl.fl_end;
758
	error = vfs_lock_file(file->f_file, F_SETLK, &lock->fl, NULL);
759
	lock->fl.fl_flags &= ~FL_SLEEP;
760 761
	lock->fl.fl_start = fl_start;
	lock->fl.fl_end = fl_end;
762

763 764 765
	switch (error) {
	case 0:
		break;
766
	case FILE_LOCK_DEFERRED:
767
		dprintk("lockd: lock still blocked error %d\n", error);
Linus Torvalds's avatar
Linus Torvalds committed
768
		nlmsvc_insert_block(block, NLM_NEVER);
Marc Eshel's avatar
Marc Eshel committed
769
		nlmsvc_release_block(block);
770
		return;
771
	default:
Linus Torvalds's avatar
Linus Torvalds committed
772
		printk(KERN_WARNING "lockd: unexpected error %d in %s!\n",
773
				-error, __func__);
Linus Torvalds's avatar
Linus Torvalds committed
774
		nlmsvc_insert_block(block, 10 * HZ);
Marc Eshel's avatar
Marc Eshel committed
775
		nlmsvc_release_block(block);
776
		return;
Linus Torvalds's avatar
Linus Torvalds committed
777 778 779 780 781 782 783
	}

callback:
	/* Lock was granted by VFS. */
	dprintk("lockd: GRANTing blocked lock.\n");
	block->b_granted = 1;

784 785 786 787
	/* keep block on the list, but don't reattempt until the RPC
	 * completes or the submission fails
	 */
	nlmsvc_insert_block(block, NLM_NEVER);
Linus Torvalds's avatar
Linus Torvalds committed
788

789 790 791 792 793 794 795 796 797
	/* Call the client -- use a soft RPC task since nlmsvc_retry_blocked
	 * will queue up a new one if this one times out
	 */
	error = nlm_async_call(block->b_call, NLMPROC_GRANTED_MSG,
				&nlmsvc_grant_ops);

	/* RPC submission failed, wait a bit and retry */
	if (error < 0)
		nlmsvc_insert_block(block, 10 * HZ);
Linus Torvalds's avatar
Linus Torvalds committed
798 799 800 801 802 803 804 805 806 807
}

/*
 * This is the callback from the RPC layer when the NLM_GRANTED_MSG
 * RPC call has succeeded or timed out.
 * Like all RPC callbacks, it is invoked by the rpciod process, so it
 * better not sleep. Therefore, we put the blocked lock on the nlm_blocked
 * chain once more in order to have it removed by lockd itself (which can
 * then sleep on the file semaphore without disrupting e.g. the nfs client).
 */
808
static void nlmsvc_grant_callback(struct rpc_task *task, void *data)
Linus Torvalds's avatar
Linus Torvalds committed
809
{
810
	struct nlm_rqst		*call = data;
811
	struct nlm_block	*block = call->a_block;
Linus Torvalds's avatar
Linus Torvalds committed
812 813 814 815
	unsigned long		timeout;

	dprintk("lockd: GRANT_MSG RPC callback\n");

816
	spin_lock(&nlm_blocked_lock);
817 818 819 820 821 822 823 824 825
	/* if the block is not on a list at this point then it has
	 * been invalidated. Don't try to requeue it.
	 *
	 * FIXME: it's possible that the block is removed from the list
	 * after this check but before the nlmsvc_insert_block. In that
	 * case it will be added back. Perhaps we need better locking
	 * for nlm_blocked?
	 */
	if (list_empty(&block->b_list))
826
		goto out;
827

Linus Torvalds's avatar
Linus Torvalds committed
828 829 830 831 832 833 834 835 836 837
	/* Technically, we should down the file semaphore here. Since we
	 * move the block towards the head of the queue only, no harm
	 * can be done, though. */
	if (task->tk_status < 0) {
		/* RPC error: Re-insert for retransmission */
		timeout = 10 * HZ;
	} else {
		/* Call was successful, now wait for client callback */
		timeout = 60 * HZ;
	}
838
	nlmsvc_insert_block_locked(block, timeout);
Linus Torvalds's avatar
Linus Torvalds committed
839
	svc_wake_up(block->b_daemon);
840
out:
841
	spin_unlock(&nlm_blocked_lock);
842 843
}

844 845 846 847
/*
 * FIXME: nlmsvc_release_block() grabs a mutex.  This is not allowed for an
 * .rpc_release rpc_call_op
 */
Adrian Bunk's avatar
Adrian Bunk committed
848
static void nlmsvc_grant_release(void *data)
849
{
850 851
	struct nlm_rqst		*call = data;
	nlmsvc_release_block(call->a_block);
Linus Torvalds's avatar
Linus Torvalds committed
852 853
}

854 855
static const struct rpc_call_ops nlmsvc_grant_ops = {
	.rpc_call_done = nlmsvc_grant_callback,
856
	.rpc_release = nlmsvc_grant_release,
857 858
};

Linus Torvalds's avatar
Linus Torvalds committed
859 860 861 862 863
/*
 * We received a GRANT_RES callback. Try to find the corresponding
 * block.
 */
void
Al Viro's avatar
Al Viro committed
864
nlmsvc_grant_reply(struct nlm_cookie *cookie, __be32 status)
Linus Torvalds's avatar
Linus Torvalds committed
865 866 867
{
	struct nlm_block	*block;

868 869 870
	dprintk("grant_reply: looking for cookie %x, s=%d \n",
		*(unsigned int *)(cookie->data), status);
	if (!(block = nlmsvc_find_block(cookie)))
Linus Torvalds's avatar
Linus Torvalds committed
871 872
		return;

873
	if (block) {
Al Viro's avatar
Al Viro committed
874
		if (status == nlm_lck_denied_grace_period) {
Linus Torvalds's avatar
Linus Torvalds committed
875 876 877 878 879
			/* Try again in a couple of seconds */
			nlmsvc_insert_block(block, 10 * HZ);
		} else {
			/* Lock is now held by client, or has been rejected.
			 * In both cases, the block should be removed. */
880
			nlmsvc_unlink_block(block);
Linus Torvalds's avatar
Linus Torvalds committed
881 882
		}
	}
883
	nlmsvc_release_block(block);
Linus Torvalds's avatar
Linus Torvalds committed
884 885
}

Marc Eshel's avatar
Marc Eshel committed
886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902
/* Helper function to handle retry of a deferred block.
 * If it is a blocking lock, call grant_blocked.
 * For a non-blocking lock or test lock, revisit the request.
 */
static void
retry_deferred_block(struct nlm_block *block)
{
	if (!(block->b_flags & B_GOT_CALLBACK))
		block->b_flags |= B_TIMED_OUT;
	nlmsvc_insert_block(block, NLM_TIMEOUT);
	dprintk("revisit block %p flags %d\n",	block, block->b_flags);
	if (block->b_deferred_req) {
		block->b_deferred_req->revisit(block->b_deferred_req, 0);
		block->b_deferred_req = NULL;
	}
}

Linus Torvalds's avatar
Linus Torvalds committed
903 904 905 906 907 908 909 910
/*
 * Retry all blocked locks that have been notified. This is where lockd
 * picks up locks that can be granted, or grant notifications that must
 * be retransmitted.
 */
unsigned long
nlmsvc_retry_blocked(void)
{
911 912 913
	unsigned long	timeout = MAX_SCHEDULE_TIMEOUT;
	struct nlm_block *block;

914
	spin_lock(&nlm_blocked_lock);
915
	while (!list_empty(&nlm_blocked) && !kthread_should_stop()) {
916
		block = list_entry(nlm_blocked.next, struct nlm_block, b_list);
Linus Torvalds's avatar
Linus Torvalds committed
917 918 919

		if (block->b_when == NLM_NEVER)
			break;
920
		if (time_after(block->b_when, jiffies)) {
921
			timeout = block->b_when - jiffies;
Linus Torvalds's avatar
Linus Torvalds committed
922
			break;
923
		}
924
		spin_unlock(&nlm_blocked_lock);
925

J. Bruce Fields's avatar
J. Bruce Fields committed
926 927
		dprintk("nlmsvc_retry_blocked(%p, when=%ld)\n",
			block, block->b_when);
Marc Eshel's avatar
Marc Eshel committed
928 929 930 931 932 933
		if (block->b_flags & B_QUEUED) {
			dprintk("nlmsvc_retry_blocked delete block (%p, granted=%d, flags=%d)\n",
				block, block->b_granted, block->b_flags);
			retry_deferred_block(block);
		} else
			nlmsvc_grant_blocked(block);
934
		spin_lock(&nlm_blocked_lock);
Linus Torvalds's avatar
Linus Torvalds committed
935
	}
936
	spin_unlock(&nlm_blocked_lock);
Linus Torvalds's avatar
Linus Torvalds committed
937

938
	return timeout;
Linus Torvalds's avatar
Linus Torvalds committed
939
}