svclock.c 25.1 KB
Newer Older
1
// SPDX-License-Identifier: GPL-2.0
Linus Torvalds's avatar
Linus Torvalds committed
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
/*
 * 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>
25
#include <linux/slab.h>
Linus Torvalds's avatar
Linus Torvalds committed
26 27 28 29
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/sunrpc/clnt.h>
30
#include <linux/sunrpc/svc_xprt.h>
Linus Torvalds's avatar
Linus Torvalds committed
31 32
#include <linux/lockd/nlm.h>
#include <linux/lockd/lockd.h>
33
#include <linux/kthread.h>
Linus Torvalds's avatar
Linus Torvalds committed
34 35 36 37 38 39 40 41 42

#define NLMDBG_FACILITY		NLMDBG_SVCLOCK

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

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

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

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

57
#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
58 59 60
static const char *nlmdbg_cookie2a(const struct nlm_cookie *cookie)
{
	/*
61 62
	 * We can get away with a static buffer because this is only called
	 * from lockd, which is single-threaded.
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
	 */
	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
86 87 88 89
/*
 * Insert a blocked lock into the global list
 */
static void
90
nlmsvc_insert_block_locked(struct nlm_block *block, unsigned long when)
Linus Torvalds's avatar
Linus Torvalds committed
91
{
92 93
	struct nlm_block *b;
	struct list_head *pos;
Linus Torvalds's avatar
Linus Torvalds committed
94 95

	dprintk("lockd: nlmsvc_insert_block(%p, %ld)\n", block, when);
96 97 98 99 100 101 102
	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
103 104 105
	if (when != NLM_NEVER) {
		if ((when += jiffies) == NLM_NEVER)
			when ++;
106 107 108 109 110 111 112 113 114
		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
115

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

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

/*
142
 * Find a block for a given lock
Linus Torvalds's avatar
Linus Torvalds committed
143 144
 */
static struct nlm_block *
145
nlmsvc_lookup_block(struct nlm_file *file, struct nlm_lock *lock)
Linus Torvalds's avatar
Linus Torvalds committed
146
{
147
	struct nlm_block	*block;
Linus Torvalds's avatar
Linus Torvalds committed
148 149 150 151 152 153
	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);
154
	list_for_each_entry(block, &nlm_blocked, b_list) {
155
		fl = &block->b_call->a_args.lock.fl;
Linus Torvalds's avatar
Linus Torvalds committed
156 157 158 159
		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,
160
				nlmdbg_cookie2a(&block->b_call->a_args.cookie));
Linus Torvalds's avatar
Linus Torvalds committed
161
		if (block->b_file == file && nlm_compare_locks(fl, &lock->fl)) {
162
			kref_get(&block->b_count);
Linus Torvalds's avatar
Linus Torvalds committed
163 164 165 166 167 168 169 170 171
			return block;
		}
	}

	return NULL;
}

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

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

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

192 193 194
	return NULL;

found:
195
	dprintk("nlmsvc_find_block(%s): block=%p\n", nlmdbg_cookie2a(cookie), block);
196
	kref_get(&block->b_count);
Linus Torvalds's avatar
Linus Torvalds committed
197 198 199 200 201 202 203 204 205 206 207 208
	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.
209 210 211 212 213
 *
 * 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
214
 */
215 216 217 218
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
219 220
{
	struct nlm_block	*block;
221
	struct nlm_rqst		*call = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
222

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

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

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

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

	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;
249
	file->f_count++;
Linus Torvalds's avatar
Linus Torvalds committed
250 251

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

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

	return block;

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

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

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

284 285 286 287 288 289
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
290 291

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

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

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

307 308 309 310 311 312 313
/*
 * 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)
314
{
315
	struct nlm_block *block, *next;
316 317

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

335 336 337 338 339 340 341 342
/*
 * 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));
343
	call->a_args.lock.caller = utsname()->nodename;
344 345 346 347 348 349 350 351
	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);
352
		if (!data)
353 354 355 356 357 358 359 360 361 362
			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)
{
363
	if (call->a_args.lock.oh.data != call->a_owner)
364
		kfree(call->a_args.lock.oh.data);
365 366

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

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

	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",
389
		block, block->b_flags, ntohl(status));
390 391 392 393

	return status;
}

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

	dprintk("lockd: nlmsvc_lock(%s/%ld, ty=%d, pi=%d, %Ld-%Ld, bl=%d)\n",
Al Viro's avatar
Al Viro committed
408 409
				file_inode(file->f_file)->i_sb->s_id,
				file_inode(file->f_file)->i_ino,
Linus Torvalds's avatar
Linus Torvalds committed
410 411 412 413 414 415
				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 */
416
	mutex_lock(&file->f_mutex);
417 418 419
	/* Get existing block (in case client is busy-waiting)
	 * or create new block
	 */
420
	block = nlmsvc_lookup_block(file, lock);
421
	if (block == NULL) {
422
		block = nlmsvc_create_block(rqstp, host, file, lock, cookie);
423 424 425
		ret = nlm_lck_denied_nolocks;
		if (block == NULL)
			goto out;
426
		lock = &block->b_call->a_args.lock;
427 428
	} else
		lock->fl.fl_flags &= ~FL_SLEEP;
Linus Torvalds's avatar
Linus Torvalds committed
429

430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445
	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
446

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

456 457 458 459
	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;
460

461
	dprintk("lockd: vfs_lock_file returned %d\n", error);
462
	switch (error) {
Linus Torvalds's avatar
Linus Torvalds committed
463
		case 0:
464 465
			ret = nlm_granted;
			goto out;
466
		case -EAGAIN:
467 468 469 470 471 472 473
			/*
			 * 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;
474
			ret = nlm_lck_denied;
475
			goto out;
476
		case FILE_LOCK_DEFERRED:
477 478 479 480 481 482
			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;
483
		case -EDEADLK:
484 485
			ret = nlm_deadlock;
			goto out;
Linus Torvalds's avatar
Linus Torvalds committed
486
		default:			/* includes ENOLCK */
487 488
			ret = nlm_lck_denied_nolocks;
			goto out;
Linus Torvalds's avatar
Linus Torvalds committed
489 490
	}

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

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

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

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

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

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

531 532 533
		ret = nlm_lck_denied_nolocks;
		goto out;
	}
534

535 536 537 538 539 540 541 542 543 544 545 546 547 548 549
	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;
550
	locks_release_private(&lock->fl);
551 552 553
	ret = nlm_lck_denied;
out:
	return ret;
Linus Torvalds's avatar
Linus Torvalds committed
554 555 556 557 558 559 560 561 562
}

/*
 * 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.
 */
563
__be32
564
nlmsvc_unlock(struct net *net, struct nlm_file *file, struct nlm_lock *lock)
Linus Torvalds's avatar
Linus Torvalds committed
565 566 567 568
{
	int	error;

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

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

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

	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.
 */
591
__be32
592
nlmsvc_cancel_blocked(struct net *net, struct nlm_file *file, struct nlm_lock *lock)
Linus Torvalds's avatar
Linus Torvalds committed
593 594
{
	struct nlm_block	*block;
595
	int status = 0;
Linus Torvalds's avatar
Linus Torvalds committed
596 597

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

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

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

619 620
/*
 * This is a callback from the filesystem for VFS file lock requests.
621
 * It will be used if lm_grant is defined and the filesystem can not
622 623 624 625 626 627 628
 * 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
629
nlmsvc_update_deferred_block(struct nlm_block *block, int result)
630 631 632 633 634 635 636 637
{
	block->b_flags |= B_GOT_CALLBACK;
	if (result == 0)
		block->b_granted = 1;
	else
		block->b_flags |= B_TIMED_OUT;
}

638
static int nlmsvc_grant_deferred(struct file_lock *fl, int result)
639 640 641 642
{
	struct nlm_block *block;
	int rc = -ENOENT;

643
	spin_lock(&nlm_blocked_lock);
644 645 646 647 648 649 650 651 652
	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;
				}
653
				nlmsvc_update_deferred_block(block, result);
654 655 656
			} else if (result == 0)
				block->b_granted = 1;

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

Linus Torvalds's avatar
Linus Torvalds committed
669 670 671 672 673 674 675 676 677 678
/*
 * 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)
{
679
	struct nlm_block	*block;
Linus Torvalds's avatar
Linus Torvalds committed
680 681

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

700 701 702 703 704 705 706 707 708 709 710
/*
 * 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;
}

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

/*
 * 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;
733
	struct nlm_lock		*lock = &block->b_call->a_args.lock;
Linus Torvalds's avatar
Linus Torvalds committed
734
	int			error;
735
	loff_t			fl_start, fl_end;
Linus Torvalds's avatar
Linus Torvalds committed
736 737 738

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

739 740
	kref_get(&block->b_count);

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

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

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

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

785 786 787 788
	/* 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
789

790 791 792 793 794 795 796 797 798
	/* 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
799 800 801 802 803 804 805 806 807 808
}

/*
 * 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).
 */
809
static void nlmsvc_grant_callback(struct rpc_task *task, void *data)
Linus Torvalds's avatar
Linus Torvalds committed
810
{
811
	struct nlm_rqst		*call = data;
812
	struct nlm_block	*block = call->a_block;
Linus Torvalds's avatar
Linus Torvalds committed
813 814 815 816
	unsigned long		timeout;

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

817
	spin_lock(&nlm_blocked_lock);
818 819 820 821 822 823 824 825 826
	/* 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))
827
		goto out;
828

Linus Torvalds's avatar
Linus Torvalds committed
829 830 831 832 833 834 835 836 837 838
	/* 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;
	}
839
	nlmsvc_insert_block_locked(block, timeout);
Linus Torvalds's avatar
Linus Torvalds committed
840
	svc_wake_up(block->b_daemon);
841
out:
842
	spin_unlock(&nlm_blocked_lock);
843 844
}

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

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

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

869 870 871
	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
872 873
		return;

874 875 876 877 878 879 880 881 882
	if (status == nlm_lck_denied_grace_period) {
		/* 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.
		 */
		nlmsvc_unlink_block(block);
Linus Torvalds's avatar
Linus Torvalds committed
883
	}
884
	nlmsvc_release_block(block);
Linus Torvalds's avatar
Linus Torvalds committed
885 886
}

887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903
/* 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
904 905 906 907 908 909 910 911
/*
 * 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)
{
912 913 914
	unsigned long	timeout = MAX_SCHEDULE_TIMEOUT;
	struct nlm_block *block;

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

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

927 928
		dprintk("nlmsvc_retry_blocked(%p, when=%ld)\n",
			block, block->b_when);
929 930 931 932 933 934
		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);
935
		spin_lock(&nlm_blocked_lock);
Linus Torvalds's avatar
Linus Torvalds committed
936
	}
937
	spin_unlock(&nlm_blocked_lock);
Linus Torvalds's avatar
Linus Torvalds committed
938

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