xref: /openbmc/linux/fs/lockd/svclock.c (revision c743b425)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  * linux/fs/lockd/svclock.c
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  * Handling of server-side locks, mostly of the blocked variety.
61da177e4SLinus Torvalds  * This is the ugliest part of lockd because we tread on very thin ice.
71da177e4SLinus Torvalds  * GRANT and CANCEL calls may get stuck, meet in mid-flight, etc.
81da177e4SLinus Torvalds  * IMNSHO introducing the grant callback into the NLM protocol was one
91da177e4SLinus Torvalds  * of the worst ideas Sun ever had. Except maybe for the idea of doing
101da177e4SLinus Torvalds  * NFS file locking at all.
111da177e4SLinus Torvalds  *
121da177e4SLinus Torvalds  * I'm trying hard to avoid race conditions by protecting most accesses
131da177e4SLinus Torvalds  * to a file's list of blocked locks through a semaphore. The global
141da177e4SLinus Torvalds  * list of blocked locks is not protected in this fashion however.
151da177e4SLinus Torvalds  * Therefore, some functions (such as the RPC callback for the async grant
161da177e4SLinus Torvalds  * call) move blocked locks towards the head of the list *while some other
171da177e4SLinus Torvalds  * process might be traversing it*. This should not be a problem in
181da177e4SLinus Torvalds  * practice, because this will only cause functions traversing the list
191da177e4SLinus Torvalds  * to visit some blocks twice.
201da177e4SLinus Torvalds  *
211da177e4SLinus Torvalds  * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
221da177e4SLinus Torvalds  */
231da177e4SLinus Torvalds 
241da177e4SLinus Torvalds #include <linux/types.h>
255a0e3ad6STejun Heo #include <linux/slab.h>
261da177e4SLinus Torvalds #include <linux/errno.h>
271da177e4SLinus Torvalds #include <linux/kernel.h>
281da177e4SLinus Torvalds #include <linux/sched.h>
291da177e4SLinus Torvalds #include <linux/sunrpc/clnt.h>
305ccb0066SStanislav Kinsbursky #include <linux/sunrpc/svc_xprt.h>
311da177e4SLinus Torvalds #include <linux/lockd/nlm.h>
321da177e4SLinus Torvalds #include <linux/lockd/lockd.h>
33d751a7cdSJeff Layton #include <linux/kthread.h>
34b840be2fSJ. Bruce Fields #include <linux/exportfs.h>
351da177e4SLinus Torvalds 
361da177e4SLinus Torvalds #define NLMDBG_FACILITY		NLMDBG_SVCLOCK
371da177e4SLinus Torvalds 
381da177e4SLinus Torvalds #ifdef CONFIG_LOCKD_V4
391da177e4SLinus Torvalds #define nlm_deadlock	nlm4_deadlock
401da177e4SLinus Torvalds #else
411da177e4SLinus Torvalds #define nlm_deadlock	nlm_lck_denied
421da177e4SLinus Torvalds #endif
431da177e4SLinus Torvalds 
446849c0caSTrond Myklebust static void nlmsvc_release_block(struct nlm_block *block);
451da177e4SLinus Torvalds static void	nlmsvc_insert_block(struct nlm_block *block, unsigned long);
4668a2d76cSOlaf Kirch static void	nlmsvc_remove_block(struct nlm_block *block);
47963d8fe5STrond Myklebust 
485e1abf8cSTrond Myklebust static int nlmsvc_setgrantargs(struct nlm_rqst *call, struct nlm_lock *lock);
495e1abf8cSTrond Myklebust static void nlmsvc_freegrantargs(struct nlm_rqst *call);
50963d8fe5STrond Myklebust static const struct rpc_call_ops nlmsvc_grant_ops;
511da177e4SLinus Torvalds 
521da177e4SLinus Torvalds /*
531da177e4SLinus Torvalds  * The list of blocked locks to retry
541da177e4SLinus Torvalds  */
5568a2d76cSOlaf Kirch static LIST_HEAD(nlm_blocked);
56f904be9cSBryan Schumaker static DEFINE_SPINLOCK(nlm_blocked_lock);
571da177e4SLinus Torvalds 
5810b89567SJeff Layton #if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
nlmdbg_cookie2a(const struct nlm_cookie * cookie)59ffa94db6STrond Myklebust static const char *nlmdbg_cookie2a(const struct nlm_cookie *cookie)
60ffa94db6STrond Myklebust {
61ffa94db6STrond Myklebust 	/*
623c519914SJeff Layton 	 * We can get away with a static buffer because this is only called
633c519914SJeff Layton 	 * from lockd, which is single-threaded.
64ffa94db6STrond Myklebust 	 */
65ffa94db6STrond Myklebust 	static char buf[2*NLM_MAXCOOKIELEN+1];
66ffa94db6STrond Myklebust 	unsigned int i, len = sizeof(buf);
67ffa94db6STrond Myklebust 	char *p = buf;
68ffa94db6STrond Myklebust 
69ffa94db6STrond Myklebust 	len--;	/* allow for trailing \0 */
70ffa94db6STrond Myklebust 	if (len < 3)
71ffa94db6STrond Myklebust 		return "???";
72ffa94db6STrond Myklebust 	for (i = 0 ; i < cookie->len ; i++) {
73ffa94db6STrond Myklebust 		if (len < 2) {
74ffa94db6STrond Myklebust 			strcpy(p-3, "...");
75ffa94db6STrond Myklebust 			break;
76ffa94db6STrond Myklebust 		}
77ffa94db6STrond Myklebust 		sprintf(p, "%02x", cookie->data[i]);
78ffa94db6STrond Myklebust 		p += 2;
79ffa94db6STrond Myklebust 		len -= 2;
80ffa94db6STrond Myklebust 	}
81ffa94db6STrond Myklebust 	*p = '\0';
82ffa94db6STrond Myklebust 
83ffa94db6STrond Myklebust 	return buf;
84ffa94db6STrond Myklebust }
85ffa94db6STrond Myklebust #endif
86ffa94db6STrond Myklebust 
871da177e4SLinus Torvalds /*
881da177e4SLinus Torvalds  * Insert a blocked lock into the global list
891da177e4SLinus Torvalds  */
901da177e4SLinus Torvalds static void
nlmsvc_insert_block_locked(struct nlm_block * block,unsigned long when)91f904be9cSBryan Schumaker nlmsvc_insert_block_locked(struct nlm_block *block, unsigned long when)
921da177e4SLinus Torvalds {
9368a2d76cSOlaf Kirch 	struct nlm_block *b;
9468a2d76cSOlaf Kirch 	struct list_head *pos;
951da177e4SLinus Torvalds 
961da177e4SLinus Torvalds 	dprintk("lockd: nlmsvc_insert_block(%p, %ld)\n", block, when);
9768a2d76cSOlaf Kirch 	if (list_empty(&block->b_list)) {
986849c0caSTrond Myklebust 		kref_get(&block->b_count);
9968a2d76cSOlaf Kirch 	} else {
10068a2d76cSOlaf Kirch 		list_del_init(&block->b_list);
10168a2d76cSOlaf Kirch 	}
10268a2d76cSOlaf Kirch 
10368a2d76cSOlaf Kirch 	pos = &nlm_blocked;
1041da177e4SLinus Torvalds 	if (when != NLM_NEVER) {
1051da177e4SLinus Torvalds 		if ((when += jiffies) == NLM_NEVER)
1061da177e4SLinus Torvalds 			when ++;
10768a2d76cSOlaf Kirch 		list_for_each(pos, &nlm_blocked) {
10868a2d76cSOlaf Kirch 			b = list_entry(pos, struct nlm_block, b_list);
10968a2d76cSOlaf Kirch 			if (time_after(b->b_when,when) || b->b_when == NLM_NEVER)
11068a2d76cSOlaf Kirch 				break;
11168a2d76cSOlaf Kirch 		}
11268a2d76cSOlaf Kirch 		/* On normal exit from the loop, pos == &nlm_blocked,
11368a2d76cSOlaf Kirch 		 * so we will be adding to the end of the list - good
11468a2d76cSOlaf Kirch 		 */
11568a2d76cSOlaf Kirch 	}
1161da177e4SLinus Torvalds 
11768a2d76cSOlaf Kirch 	list_add_tail(&block->b_list, pos);
1181da177e4SLinus Torvalds 	block->b_when = when;
1191da177e4SLinus Torvalds }
1201da177e4SLinus Torvalds 
nlmsvc_insert_block(struct nlm_block * block,unsigned long when)121f904be9cSBryan Schumaker static void nlmsvc_insert_block(struct nlm_block *block, unsigned long when)
122f904be9cSBryan Schumaker {
123f904be9cSBryan Schumaker 	spin_lock(&nlm_blocked_lock);
124f904be9cSBryan Schumaker 	nlmsvc_insert_block_locked(block, when);
125f904be9cSBryan Schumaker 	spin_unlock(&nlm_blocked_lock);
126f904be9cSBryan Schumaker }
127f904be9cSBryan Schumaker 
1281da177e4SLinus Torvalds /*
1291da177e4SLinus Torvalds  * Remove a block from the global list
1301da177e4SLinus Torvalds  */
13168a2d76cSOlaf Kirch static inline void
nlmsvc_remove_block(struct nlm_block * block)1321da177e4SLinus Torvalds nlmsvc_remove_block(struct nlm_block *block)
1331da177e4SLinus Torvalds {
134f904be9cSBryan Schumaker 	spin_lock(&nlm_blocked_lock);
135be2be5f7SAlexander Aring 	if (!list_empty(&block->b_list)) {
13668a2d76cSOlaf Kirch 		list_del_init(&block->b_list);
137f904be9cSBryan Schumaker 		spin_unlock(&nlm_blocked_lock);
1386849c0caSTrond Myklebust 		nlmsvc_release_block(block);
139be2be5f7SAlexander Aring 		return;
1401da177e4SLinus Torvalds 	}
141be2be5f7SAlexander Aring 	spin_unlock(&nlm_blocked_lock);
1421da177e4SLinus Torvalds }
1431da177e4SLinus Torvalds 
1441da177e4SLinus Torvalds /*
145d9f6eb75STrond Myklebust  * Find a block for a given lock
1461da177e4SLinus Torvalds  */
1471da177e4SLinus Torvalds static struct nlm_block *
nlmsvc_lookup_block(struct nlm_file * file,struct nlm_lock * lock)148d9f6eb75STrond Myklebust nlmsvc_lookup_block(struct nlm_file *file, struct nlm_lock *lock)
1491da177e4SLinus Torvalds {
15068a2d76cSOlaf Kirch 	struct nlm_block	*block;
1511da177e4SLinus Torvalds 	struct file_lock	*fl;
1521da177e4SLinus Torvalds 
1531da177e4SLinus Torvalds 	dprintk("lockd: nlmsvc_lookup_block f=%p pd=%d %Ld-%Ld ty=%d\n",
1541da177e4SLinus Torvalds 				file, lock->fl.fl_pid,
1551da177e4SLinus Torvalds 				(long long)lock->fl.fl_start,
1561da177e4SLinus Torvalds 				(long long)lock->fl.fl_end, lock->fl.fl_type);
157be2be5f7SAlexander Aring 	spin_lock(&nlm_blocked_lock);
15868a2d76cSOlaf Kirch 	list_for_each_entry(block, &nlm_blocked, b_list) {
15992737230STrond Myklebust 		fl = &block->b_call->a_args.lock.fl;
1601da177e4SLinus Torvalds 		dprintk("lockd: check f=%p pd=%d %Ld-%Ld ty=%d cookie=%s\n",
1611da177e4SLinus Torvalds 				block->b_file, fl->fl_pid,
1621da177e4SLinus Torvalds 				(long long)fl->fl_start,
1631da177e4SLinus Torvalds 				(long long)fl->fl_end, fl->fl_type,
16492737230STrond Myklebust 				nlmdbg_cookie2a(&block->b_call->a_args.cookie));
1651da177e4SLinus Torvalds 		if (block->b_file == file && nlm_compare_locks(fl, &lock->fl)) {
1666849c0caSTrond Myklebust 			kref_get(&block->b_count);
167be2be5f7SAlexander Aring 			spin_unlock(&nlm_blocked_lock);
1681da177e4SLinus Torvalds 			return block;
1691da177e4SLinus Torvalds 		}
1701da177e4SLinus Torvalds 	}
171be2be5f7SAlexander Aring 	spin_unlock(&nlm_blocked_lock);
1721da177e4SLinus Torvalds 
1731da177e4SLinus Torvalds 	return NULL;
1741da177e4SLinus Torvalds }
1751da177e4SLinus Torvalds 
nlm_cookie_match(struct nlm_cookie * a,struct nlm_cookie * b)1761da177e4SLinus Torvalds static inline int nlm_cookie_match(struct nlm_cookie *a, struct nlm_cookie *b)
1771da177e4SLinus Torvalds {
1781da177e4SLinus Torvalds 	if (a->len != b->len)
1791da177e4SLinus Torvalds 		return 0;
1801da177e4SLinus Torvalds 	if (memcmp(a->data, b->data, a->len))
1811da177e4SLinus Torvalds 		return 0;
1821da177e4SLinus Torvalds 	return 1;
1831da177e4SLinus Torvalds }
1841da177e4SLinus Torvalds 
1851da177e4SLinus Torvalds /*
1861da177e4SLinus Torvalds  * Find a block with a given NLM cookie.
1871da177e4SLinus Torvalds  */
1881da177e4SLinus Torvalds static inline struct nlm_block *
nlmsvc_find_block(struct nlm_cookie * cookie)18939be4502SOlaf Kirch nlmsvc_find_block(struct nlm_cookie *cookie)
1901da177e4SLinus Torvalds {
1911da177e4SLinus Torvalds 	struct nlm_block *block;
1921da177e4SLinus Torvalds 
193be2be5f7SAlexander Aring 	spin_lock(&nlm_blocked_lock);
19468a2d76cSOlaf Kirch 	list_for_each_entry(block, &nlm_blocked, b_list) {
19539be4502SOlaf Kirch 		if (nlm_cookie_match(&block->b_call->a_args.cookie,cookie))
19668a2d76cSOlaf Kirch 			goto found;
1971da177e4SLinus Torvalds 	}
198be2be5f7SAlexander Aring 	spin_unlock(&nlm_blocked_lock);
1991da177e4SLinus Torvalds 
20068a2d76cSOlaf Kirch 	return NULL;
20168a2d76cSOlaf Kirch 
20268a2d76cSOlaf Kirch found:
20339be4502SOlaf Kirch 	dprintk("nlmsvc_find_block(%s): block=%p\n", nlmdbg_cookie2a(cookie), block);
2046849c0caSTrond Myklebust 	kref_get(&block->b_count);
205be2be5f7SAlexander Aring 	spin_unlock(&nlm_blocked_lock);
2061da177e4SLinus Torvalds 	return block;
2071da177e4SLinus Torvalds }
2081da177e4SLinus Torvalds 
2091da177e4SLinus Torvalds /*
2101da177e4SLinus Torvalds  * Create a block and initialize it.
2111da177e4SLinus Torvalds  *
2121da177e4SLinus Torvalds  * Note: we explicitly set the cookie of the grant reply to that of
2131da177e4SLinus Torvalds  * the blocked lock request. The spec explicitly mentions that the client
2141da177e4SLinus Torvalds  * should _not_ rely on the callback containing the same cookie as the
2151da177e4SLinus Torvalds  * request, but (as I found out later) that's because some implementations
2161da177e4SLinus Torvalds  * do just this. Never mind the standards comittees, they support our
2171da177e4SLinus Torvalds  * logging industries.
21839be4502SOlaf Kirch  *
21939be4502SOlaf Kirch  * 10 years later: I hope we can safely ignore these old and broken
22039be4502SOlaf Kirch  * clients by now. Let's fix this so we can uniquely identify an incoming
22139be4502SOlaf Kirch  * GRANTED_RES message by cookie, without having to rely on the client's IP
22239be4502SOlaf Kirch  * address. --okir
2231da177e4SLinus Torvalds  */
224255129d1STrond Myklebust 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)225255129d1STrond Myklebust nlmsvc_create_block(struct svc_rqst *rqstp, struct nlm_host *host,
226255129d1STrond Myklebust 		    struct nlm_file *file, struct nlm_lock *lock,
227255129d1STrond Myklebust 		    struct nlm_cookie *cookie)
2281da177e4SLinus Torvalds {
2291da177e4SLinus Torvalds 	struct nlm_block	*block;
23092737230STrond Myklebust 	struct nlm_rqst		*call = NULL;
2311da177e4SLinus Torvalds 
23292737230STrond Myklebust 	call = nlm_alloc_call(host);
23392737230STrond Myklebust 	if (call == NULL)
23492737230STrond Myklebust 		return NULL;
23592737230STrond Myklebust 
2361da177e4SLinus Torvalds 	/* Allocate memory for block, and initialize arguments */
23792737230STrond Myklebust 	block = kzalloc(sizeof(*block), GFP_KERNEL);
23892737230STrond Myklebust 	if (block == NULL)
2391da177e4SLinus Torvalds 		goto failed;
2406849c0caSTrond Myklebust 	kref_init(&block->b_count);
24168a2d76cSOlaf Kirch 	INIT_LIST_HEAD(&block->b_list);
24268a2d76cSOlaf Kirch 	INIT_LIST_HEAD(&block->b_flist);
2431da177e4SLinus Torvalds 
24492737230STrond Myklebust 	if (!nlmsvc_setgrantargs(call, lock))
2451da177e4SLinus Torvalds 		goto failed_free;
2461da177e4SLinus Torvalds 
2471da177e4SLinus Torvalds 	/* Set notifier function for VFS, and init args */
24892737230STrond Myklebust 	call->a_args.lock.fl.fl_flags |= FL_SLEEP;
24992737230STrond Myklebust 	call->a_args.lock.fl.fl_lmops = &nlmsvc_lock_operations;
25039be4502SOlaf Kirch 	nlmclnt_next_cookie(&call->a_args.cookie);
2511da177e4SLinus Torvalds 
2521da177e4SLinus Torvalds 	dprintk("lockd: created block %p...\n", block);
2531da177e4SLinus Torvalds 
2541da177e4SLinus Torvalds 	/* Create and initialize the block */
2551da177e4SLinus Torvalds 	block->b_daemon = rqstp->rq_server;
2561da177e4SLinus Torvalds 	block->b_host   = host;
2571da177e4SLinus Torvalds 	block->b_file   = file;
258d9f6eb75STrond Myklebust 	file->f_count++;
2591da177e4SLinus Torvalds 
2601da177e4SLinus Torvalds 	/* Add to file's list of blocks */
26168a2d76cSOlaf Kirch 	list_add(&block->b_flist, &file->f_blocks);
2621da177e4SLinus Torvalds 
2631da177e4SLinus Torvalds 	/* Set up RPC arguments for callback */
26492737230STrond Myklebust 	block->b_call = call;
2651da177e4SLinus Torvalds 	call->a_flags   = RPC_TASK_ASYNC;
26692737230STrond Myklebust 	call->a_block = block;
2671da177e4SLinus Torvalds 
2681da177e4SLinus Torvalds 	return block;
2691da177e4SLinus Torvalds 
2701da177e4SLinus Torvalds failed_free:
2711da177e4SLinus Torvalds 	kfree(block);
2721da177e4SLinus Torvalds failed:
2737db836d4SChuck Lever 	nlmsvc_release_call(call);
2741da177e4SLinus Torvalds 	return NULL;
2751da177e4SLinus Torvalds }
2761da177e4SLinus Torvalds 
2771da177e4SLinus Torvalds /*
2783c61eecbSJ. Bruce Fields  * Delete a block.
2791da177e4SLinus Torvalds  * It is the caller's responsibility to check whether the file
2801da177e4SLinus Torvalds  * can be closed hereafter.
2811da177e4SLinus Torvalds  */
nlmsvc_unlink_block(struct nlm_block * block)2826849c0caSTrond Myklebust static int nlmsvc_unlink_block(struct nlm_block *block)
2831da177e4SLinus Torvalds {
28409c7938cSTrond Myklebust 	int status;
2856849c0caSTrond Myklebust 	dprintk("lockd: unlinking block %p...\n", block);
2861da177e4SLinus Torvalds 
2871da177e4SLinus Torvalds 	/* Remove block from list */
288cb03f94fSNeilBrown 	status = locks_delete_block(&block->b_call->a_args.lock.fl);
2891da177e4SLinus Torvalds 	nlmsvc_remove_block(block);
29064a318eeSJ. Bruce Fields 	return status;
2911da177e4SLinus Torvalds }
2921da177e4SLinus Torvalds 
nlmsvc_free_block(struct kref * kref)2936849c0caSTrond Myklebust static void nlmsvc_free_block(struct kref *kref)
2946849c0caSTrond Myklebust {
2956849c0caSTrond Myklebust 	struct nlm_block *block = container_of(kref, struct nlm_block, b_count);
2966849c0caSTrond Myklebust 	struct nlm_file		*file = block->b_file;
2976849c0caSTrond Myklebust 
2986849c0caSTrond Myklebust 	dprintk("lockd: freeing block %p...\n", block);
2996849c0caSTrond Myklebust 
3001da177e4SLinus Torvalds 	/* Remove block from file's list of blocks */
30168a2d76cSOlaf Kirch 	list_del_init(&block->b_flist);
30289e63ef6SNeil Brown 	mutex_unlock(&file->f_mutex);
3031da177e4SLinus Torvalds 
30492737230STrond Myklebust 	nlmsvc_freegrantargs(block->b_call);
3057db836d4SChuck Lever 	nlmsvc_release_call(block->b_call);
306d9f6eb75STrond Myklebust 	nlm_release_file(block->b_file);
3071da177e4SLinus Torvalds 	kfree(block);
3086849c0caSTrond Myklebust }
3096849c0caSTrond Myklebust 
nlmsvc_release_block(struct nlm_block * block)3106849c0caSTrond Myklebust static void nlmsvc_release_block(struct nlm_block *block)
3116849c0caSTrond Myklebust {
3126849c0caSTrond Myklebust 	if (block != NULL)
313c5aa1e55SAl Viro 		kref_put_mutex(&block->b_count, nlmsvc_free_block, &block->b_file->f_mutex);
3141da177e4SLinus Torvalds }
3151da177e4SLinus Torvalds 
316f2af793dSOlaf Kirch /*
317f2af793dSOlaf Kirch  * Loop over all blocks and delete blocks held by
318f2af793dSOlaf Kirch  * a matching host.
319f2af793dSOlaf Kirch  */
nlmsvc_traverse_blocks(struct nlm_host * host,struct nlm_file * file,nlm_host_match_fn_t match)320f2af793dSOlaf Kirch void nlmsvc_traverse_blocks(struct nlm_host *host,
321f2af793dSOlaf Kirch 			struct nlm_file *file,
322f2af793dSOlaf Kirch 			nlm_host_match_fn_t match)
323d9f6eb75STrond Myklebust {
32468a2d76cSOlaf Kirch 	struct nlm_block *block, *next;
325d9f6eb75STrond Myklebust 
326d9f6eb75STrond Myklebust restart:
32789e63ef6SNeil Brown 	mutex_lock(&file->f_mutex);
328be2be5f7SAlexander Aring 	spin_lock(&nlm_blocked_lock);
32968a2d76cSOlaf Kirch 	list_for_each_entry_safe(block, next, &file->f_blocks, b_flist) {
330f2af793dSOlaf Kirch 		if (!match(block->b_host, host))
331d9f6eb75STrond Myklebust 			continue;
33268a2d76cSOlaf Kirch 		/* Do not destroy blocks that are not on
33368a2d76cSOlaf Kirch 		 * the global retry list - why? */
33468a2d76cSOlaf Kirch 		if (list_empty(&block->b_list))
335d9f6eb75STrond Myklebust 			continue;
336d9f6eb75STrond Myklebust 		kref_get(&block->b_count);
337be2be5f7SAlexander Aring 		spin_unlock(&nlm_blocked_lock);
33889e63ef6SNeil Brown 		mutex_unlock(&file->f_mutex);
339d9f6eb75STrond Myklebust 		nlmsvc_unlink_block(block);
340d9f6eb75STrond Myklebust 		nlmsvc_release_block(block);
341d9f6eb75STrond Myklebust 		goto restart;
342d9f6eb75STrond Myklebust 	}
343be2be5f7SAlexander Aring 	spin_unlock(&nlm_blocked_lock);
34489e63ef6SNeil Brown 	mutex_unlock(&file->f_mutex);
345d9f6eb75STrond Myklebust }
346d9f6eb75STrond Myklebust 
34789e0edfbSBenjamin Coddington static struct nlm_lockowner *
nlmsvc_get_lockowner(struct nlm_lockowner * lockowner)34889e0edfbSBenjamin Coddington nlmsvc_get_lockowner(struct nlm_lockowner *lockowner)
34989e0edfbSBenjamin Coddington {
35089e0edfbSBenjamin Coddington 	refcount_inc(&lockowner->count);
35189e0edfbSBenjamin Coddington 	return lockowner;
35289e0edfbSBenjamin Coddington }
35389e0edfbSBenjamin Coddington 
nlmsvc_put_lockowner(struct nlm_lockowner * lockowner)354184cefbeSBenjamin Coddington void nlmsvc_put_lockowner(struct nlm_lockowner *lockowner)
35589e0edfbSBenjamin Coddington {
35689e0edfbSBenjamin Coddington 	if (!refcount_dec_and_lock(&lockowner->count, &lockowner->host->h_lock))
35789e0edfbSBenjamin Coddington 		return;
35889e0edfbSBenjamin Coddington 	list_del(&lockowner->list);
35989e0edfbSBenjamin Coddington 	spin_unlock(&lockowner->host->h_lock);
36089e0edfbSBenjamin Coddington 	nlmsvc_release_host(lockowner->host);
36189e0edfbSBenjamin Coddington 	kfree(lockowner);
36289e0edfbSBenjamin Coddington }
36389e0edfbSBenjamin Coddington 
__nlmsvc_find_lockowner(struct nlm_host * host,pid_t pid)36489e0edfbSBenjamin Coddington static struct nlm_lockowner *__nlmsvc_find_lockowner(struct nlm_host *host, pid_t pid)
36589e0edfbSBenjamin Coddington {
36689e0edfbSBenjamin Coddington 	struct nlm_lockowner *lockowner;
36789e0edfbSBenjamin Coddington 	list_for_each_entry(lockowner, &host->h_lockowners, list) {
36889e0edfbSBenjamin Coddington 		if (lockowner->pid != pid)
36989e0edfbSBenjamin Coddington 			continue;
37089e0edfbSBenjamin Coddington 		return nlmsvc_get_lockowner(lockowner);
37189e0edfbSBenjamin Coddington 	}
37289e0edfbSBenjamin Coddington 	return NULL;
37389e0edfbSBenjamin Coddington }
37489e0edfbSBenjamin Coddington 
nlmsvc_find_lockowner(struct nlm_host * host,pid_t pid)37589e0edfbSBenjamin Coddington static struct nlm_lockowner *nlmsvc_find_lockowner(struct nlm_host *host, pid_t pid)
37689e0edfbSBenjamin Coddington {
37789e0edfbSBenjamin Coddington 	struct nlm_lockowner *res, *new = NULL;
37889e0edfbSBenjamin Coddington 
37989e0edfbSBenjamin Coddington 	spin_lock(&host->h_lock);
38089e0edfbSBenjamin Coddington 	res = __nlmsvc_find_lockowner(host, pid);
38189e0edfbSBenjamin Coddington 
38289e0edfbSBenjamin Coddington 	if (res == NULL) {
38389e0edfbSBenjamin Coddington 		spin_unlock(&host->h_lock);
38489e0edfbSBenjamin Coddington 		new = kmalloc(sizeof(*res), GFP_KERNEL);
38589e0edfbSBenjamin Coddington 		spin_lock(&host->h_lock);
38689e0edfbSBenjamin Coddington 		res = __nlmsvc_find_lockowner(host, pid);
38789e0edfbSBenjamin Coddington 		if (res == NULL && new != NULL) {
38889e0edfbSBenjamin Coddington 			res = new;
38989e0edfbSBenjamin Coddington 			/* fs/locks.c will manage the refcount through lock_ops */
39089e0edfbSBenjamin Coddington 			refcount_set(&new->count, 1);
39189e0edfbSBenjamin Coddington 			new->pid = pid;
39289e0edfbSBenjamin Coddington 			new->host = nlm_get_host(host);
39389e0edfbSBenjamin Coddington 			list_add(&new->list, &host->h_lockowners);
39489e0edfbSBenjamin Coddington 			new = NULL;
39589e0edfbSBenjamin Coddington 		}
39689e0edfbSBenjamin Coddington 	}
39789e0edfbSBenjamin Coddington 
39889e0edfbSBenjamin Coddington 	spin_unlock(&host->h_lock);
39989e0edfbSBenjamin Coddington 	kfree(new);
40089e0edfbSBenjamin Coddington 	return res;
40189e0edfbSBenjamin Coddington }
40289e0edfbSBenjamin Coddington 
40389e0edfbSBenjamin Coddington void
nlmsvc_release_lockowner(struct nlm_lock * lock)40489e0edfbSBenjamin Coddington nlmsvc_release_lockowner(struct nlm_lock *lock)
40589e0edfbSBenjamin Coddington {
40689e0edfbSBenjamin Coddington 	if (lock->fl.fl_owner)
40789e0edfbSBenjamin Coddington 		nlmsvc_put_lockowner(lock->fl.fl_owner);
40889e0edfbSBenjamin Coddington }
40989e0edfbSBenjamin Coddington 
nlmsvc_locks_init_private(struct file_lock * fl,struct nlm_host * host,pid_t pid)41089e0edfbSBenjamin Coddington void nlmsvc_locks_init_private(struct file_lock *fl, struct nlm_host *host,
41189e0edfbSBenjamin Coddington 						pid_t pid)
41289e0edfbSBenjamin Coddington {
41389e0edfbSBenjamin Coddington 	fl->fl_owner = nlmsvc_find_lockowner(host, pid);
41489e0edfbSBenjamin Coddington }
41589e0edfbSBenjamin Coddington 
4161da177e4SLinus Torvalds /*
4175e1abf8cSTrond Myklebust  * Initialize arguments for GRANTED call. The nlm_rqst structure
4185e1abf8cSTrond Myklebust  * has been cleared already.
4195e1abf8cSTrond Myklebust  */
nlmsvc_setgrantargs(struct nlm_rqst * call,struct nlm_lock * lock)4205e1abf8cSTrond Myklebust static int nlmsvc_setgrantargs(struct nlm_rqst *call, struct nlm_lock *lock)
4215e1abf8cSTrond Myklebust {
4225e1abf8cSTrond Myklebust 	locks_copy_lock(&call->a_args.lock.fl, &lock->fl);
4235e1abf8cSTrond Myklebust 	memcpy(&call->a_args.lock.fh, &lock->fh, sizeof(call->a_args.lock.fh));
424e9ff3990SSerge E. Hallyn 	call->a_args.lock.caller = utsname()->nodename;
4255e1abf8cSTrond Myklebust 	call->a_args.lock.oh.len = lock->oh.len;
4265e1abf8cSTrond Myklebust 
4275e1abf8cSTrond Myklebust 	/* set default data area */
4285e1abf8cSTrond Myklebust 	call->a_args.lock.oh.data = call->a_owner;
429646d73e9SBenjamin Coddington 	call->a_args.lock.svid = ((struct nlm_lockowner *)lock->fl.fl_owner)->pid;
4305e1abf8cSTrond Myklebust 
4315e1abf8cSTrond Myklebust 	if (lock->oh.len > NLMCLNT_OHSIZE) {
4325e1abf8cSTrond Myklebust 		void *data = kmalloc(lock->oh.len, GFP_KERNEL);
43392737230STrond Myklebust 		if (!data)
4345e1abf8cSTrond Myklebust 			return 0;
4355e1abf8cSTrond Myklebust 		call->a_args.lock.oh.data = (u8 *) data;
4365e1abf8cSTrond Myklebust 	}
4375e1abf8cSTrond Myklebust 
4385e1abf8cSTrond Myklebust 	memcpy(call->a_args.lock.oh.data, lock->oh.data, lock->oh.len);
4395e1abf8cSTrond Myklebust 	return 1;
4405e1abf8cSTrond Myklebust }
4415e1abf8cSTrond Myklebust 
nlmsvc_freegrantargs(struct nlm_rqst * call)4425e1abf8cSTrond Myklebust static void nlmsvc_freegrantargs(struct nlm_rqst *call)
4435e1abf8cSTrond Myklebust {
44492737230STrond Myklebust 	if (call->a_args.lock.oh.data != call->a_owner)
4455e1abf8cSTrond Myklebust 		kfree(call->a_args.lock.oh.data);
446a9e61e25SFelix Blyakher 
447a9e61e25SFelix Blyakher 	locks_release_private(&call->a_args.lock.fl);
4485e1abf8cSTrond Myklebust }
4495e1abf8cSTrond Myklebust 
4505e1abf8cSTrond Myklebust /*
4512b36f412SMarc Eshel  * Deferred lock request handling for non-blocking lock
4522b36f412SMarc Eshel  */
453ca5c8cdeSAl Viro static __be32
nlmsvc_defer_lock_rqst(struct svc_rqst * rqstp,struct nlm_block * block)4542b36f412SMarc Eshel nlmsvc_defer_lock_rqst(struct svc_rqst *rqstp, struct nlm_block *block)
4552b36f412SMarc Eshel {
456ca5c8cdeSAl Viro 	__be32 status = nlm_lck_denied_nolocks;
4572b36f412SMarc Eshel 
4582b36f412SMarc Eshel 	block->b_flags |= B_QUEUED;
4592b36f412SMarc Eshel 
4602b36f412SMarc Eshel 	nlmsvc_insert_block(block, NLM_TIMEOUT);
4612b36f412SMarc Eshel 
4622b36f412SMarc Eshel 	block->b_cache_req = &rqstp->rq_chandle;
4632b36f412SMarc Eshel 	if (rqstp->rq_chandle.defer) {
4642b36f412SMarc Eshel 		block->b_deferred_req =
4652b36f412SMarc Eshel 			rqstp->rq_chandle.defer(block->b_cache_req);
4662b36f412SMarc Eshel 		if (block->b_deferred_req != NULL)
4672b36f412SMarc Eshel 			status = nlm_drop_reply;
4682b36f412SMarc Eshel 	}
4692b36f412SMarc Eshel 	dprintk("lockd: nlmsvc_defer_lock_rqst block %p flags %d status %d\n",
470ca5c8cdeSAl Viro 		block, block->b_flags, ntohl(status));
4712b36f412SMarc Eshel 
4722b36f412SMarc Eshel 	return status;
4732b36f412SMarc Eshel }
4742b36f412SMarc Eshel 
4752b36f412SMarc Eshel /*
4761da177e4SLinus Torvalds  * Attempt to establish a lock, and if it can't be granted, block it
4771da177e4SLinus Torvalds  * if required.
4781da177e4SLinus Torvalds  */
47952921e02SAl Viro __be32
nlmsvc_lock(struct svc_rqst * rqstp,struct nlm_file * file,struct nlm_host * host,struct nlm_lock * lock,int wait,struct nlm_cookie * cookie,int reclaim)4801da177e4SLinus Torvalds nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file,
4816cde4de8SJeff Layton 	    struct nlm_host *host, struct nlm_lock *lock, int wait,
482b2b50289SJ. Bruce Fields 	    struct nlm_cookie *cookie, int reclaim)
4831da177e4SLinus Torvalds {
48440595cdcSJ. Bruce Fields #if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
485b840be2fSJ. Bruce Fields 	struct inode		*inode = nlmsvc_file_inode(file);
48640595cdcSJ. Bruce Fields #endif
48740595cdcSJ. Bruce Fields 	struct nlm_block	*block = NULL;
4881da177e4SLinus Torvalds 	int			error;
4897f024fcdSJ. Bruce Fields 	int			mode;
490b840be2fSJ. Bruce Fields 	int			async_block = 0;
49152921e02SAl Viro 	__be32			ret;
4921da177e4SLinus Torvalds 
4931da177e4SLinus Torvalds 	dprintk("lockd: nlmsvc_lock(%s/%ld, ty=%d, pi=%d, %Ld-%Ld, bl=%d)\n",
494b840be2fSJ. Bruce Fields 				inode->i_sb->s_id, inode->i_ino,
4951da177e4SLinus Torvalds 				lock->fl.fl_type, lock->fl.fl_pid,
4961da177e4SLinus Torvalds 				(long long)lock->fl.fl_start,
4971da177e4SLinus Torvalds 				(long long)lock->fl.fl_end,
4981da177e4SLinus Torvalds 				wait);
4991da177e4SLinus Torvalds 
50040595cdcSJ. Bruce Fields 	if (nlmsvc_file_file(file)->f_op->lock) {
501b840be2fSJ. Bruce Fields 		async_block = wait;
502b840be2fSJ. Bruce Fields 		wait = 0;
503b840be2fSJ. Bruce Fields 	}
504b840be2fSJ. Bruce Fields 
5051da177e4SLinus Torvalds 	/* Lock file against concurrent access */
50689e63ef6SNeil Brown 	mutex_lock(&file->f_mutex);
507f8120480SMarc Eshel 	/* Get existing block (in case client is busy-waiting)
508f8120480SMarc Eshel 	 * or create new block
509f8120480SMarc Eshel 	 */
510d9f6eb75STrond Myklebust 	block = nlmsvc_lookup_block(file, lock);
51109c7938cSTrond Myklebust 	if (block == NULL) {
512560de0e6SJ. Bruce Fields 		block = nlmsvc_create_block(rqstp, host, file, lock, cookie);
513f8120480SMarc Eshel 		ret = nlm_lck_denied_nolocks;
514f8120480SMarc Eshel 		if (block == NULL)
515f8120480SMarc Eshel 			goto out;
51692737230STrond Myklebust 		lock = &block->b_call->a_args.lock;
517f8120480SMarc Eshel 	} else
518f8120480SMarc Eshel 		lock->fl.fl_flags &= ~FL_SLEEP;
5191da177e4SLinus Torvalds 
5201a8322b2SMarc Eshel 	if (block->b_flags & B_QUEUED) {
5211a8322b2SMarc Eshel 		dprintk("lockd: nlmsvc_lock deferred block %p flags %d\n",
5221a8322b2SMarc Eshel 							block, block->b_flags);
5231a8322b2SMarc Eshel 		if (block->b_granted) {
5241a8322b2SMarc Eshel 			nlmsvc_unlink_block(block);
5251a8322b2SMarc Eshel 			ret = nlm_granted;
5261a8322b2SMarc Eshel 			goto out;
5271a8322b2SMarc Eshel 		}
5281a8322b2SMarc Eshel 		if (block->b_flags & B_TIMED_OUT) {
5291a8322b2SMarc Eshel 			nlmsvc_unlink_block(block);
5301a8322b2SMarc Eshel 			ret = nlm_lck_denied;
5311a8322b2SMarc Eshel 			goto out;
5321a8322b2SMarc Eshel 		}
5331a8322b2SMarc Eshel 		ret = nlm_drop_reply;
5341a8322b2SMarc Eshel 		goto out;
5351a8322b2SMarc Eshel 	}
5361a8322b2SMarc Eshel 
5375ccb0066SStanislav Kinsbursky 	if (locks_in_grace(SVC_NET(rqstp)) && !reclaim) {
538b2b50289SJ. Bruce Fields 		ret = nlm_lck_denied_grace_period;
539b2b50289SJ. Bruce Fields 		goto out;
540b2b50289SJ. Bruce Fields 	}
5415ccb0066SStanislav Kinsbursky 	if (reclaim && !locks_in_grace(SVC_NET(rqstp))) {
542d22b1cffSJ. Bruce Fields 		ret = nlm_lck_denied_grace_period;
543d22b1cffSJ. Bruce Fields 		goto out;
544d22b1cffSJ. Bruce Fields 	}
545b2b50289SJ. Bruce Fields 
5461a8322b2SMarc Eshel 	if (!wait)
5471a8322b2SMarc Eshel 		lock->fl.fl_flags &= ~FL_SLEEP;
5487f024fcdSJ. Bruce Fields 	mode = lock_to_openmode(&lock->fl);
5497f024fcdSJ. Bruce Fields 	error = vfs_lock_file(file->f_file[mode], F_SETLK, &lock->fl, NULL);
55009c7938cSTrond Myklebust 	lock->fl.fl_flags &= ~FL_SLEEP;
5511da177e4SLinus Torvalds 
5521a8322b2SMarc Eshel 	dprintk("lockd: vfs_lock_file returned %d\n", error);
55309c7938cSTrond Myklebust 	switch (error) {
5541da177e4SLinus Torvalds 		case 0:
55515dadef9SAndy Adamson 			ret = nlm_granted;
55615dadef9SAndy Adamson 			goto out;
55709c7938cSTrond Myklebust 		case -EAGAIN:
558e33d1ea6SMiklos Szeredi 			/*
559e33d1ea6SMiklos Szeredi 			 * If this is a blocking request for an
560e33d1ea6SMiklos Szeredi 			 * already pending lock request then we need
561e33d1ea6SMiklos Szeredi 			 * to put it back on lockd's block list
562e33d1ea6SMiklos Szeredi 			 */
563e33d1ea6SMiklos Szeredi 			if (wait)
5649d9b87c1SJ. Bruce Fields 				break;
565b840be2fSJ. Bruce Fields 			ret = async_block ? nlm_lck_blocked : nlm_lck_denied;
566e33d1ea6SMiklos Szeredi 			goto out;
567bde74e4bSMiklos Szeredi 		case FILE_LOCK_DEFERRED:
5681a8322b2SMarc Eshel 			if (wait)
5691a8322b2SMarc Eshel 				break;
5701a8322b2SMarc Eshel 			/* Filesystem lock operation is in progress
5711a8322b2SMarc Eshel 			   Add it to the queue waiting for callback */
5721a8322b2SMarc Eshel 			ret = nlmsvc_defer_lock_rqst(rqstp, block);
5731a8322b2SMarc Eshel 			goto out;
57409c7938cSTrond Myklebust 		case -EDEADLK:
57515dadef9SAndy Adamson 			ret = nlm_deadlock;
57615dadef9SAndy Adamson 			goto out;
5771da177e4SLinus Torvalds 		default:			/* includes ENOLCK */
57815dadef9SAndy Adamson 			ret = nlm_lck_denied_nolocks;
57915dadef9SAndy Adamson 			goto out;
5801da177e4SLinus Torvalds 	}
5811da177e4SLinus Torvalds 
58209c7938cSTrond Myklebust 	ret = nlm_lck_blocked;
5831da177e4SLinus Torvalds 
5841da177e4SLinus Torvalds 	/* Append to list of blocked */
585f8120480SMarc Eshel 	nlmsvc_insert_block(block, NLM_NEVER);
58615dadef9SAndy Adamson out:
58789e63ef6SNeil Brown 	mutex_unlock(&file->f_mutex);
5886849c0caSTrond Myklebust 	nlmsvc_release_block(block);
58915dadef9SAndy Adamson 	dprintk("lockd: nlmsvc_lock returned %u\n", ret);
59015dadef9SAndy Adamson 	return ret;
5911da177e4SLinus Torvalds }
5921da177e4SLinus Torvalds 
5931da177e4SLinus Torvalds /*
5941da177e4SLinus Torvalds  * Test for presence of a conflicting lock.
5951da177e4SLinus Torvalds  */
59652921e02SAl Viro __be32
nlmsvc_testlock(struct svc_rqst * rqstp,struct nlm_file * file,struct nlm_host * host,struct nlm_lock * lock,struct nlm_lock * conflock,struct nlm_cookie * cookie)59785f3f1b3SMarc Eshel nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file,
5988f920d5eSJeff Layton 		struct nlm_host *host, struct nlm_lock *lock,
5998f920d5eSJeff Layton 		struct nlm_lock *conflock, struct nlm_cookie *cookie)
6001da177e4SLinus Torvalds {
6015ea0d750SMarc Eshel 	int			error;
6027f024fcdSJ. Bruce Fields 	int			mode;
6035ea0d750SMarc Eshel 	__be32			ret;
6045ea0d750SMarc Eshel 
6051da177e4SLinus Torvalds 	dprintk("lockd: nlmsvc_testlock(%s/%ld, ty=%d, %Ld-%Ld)\n",
606a81041b7SJ. Bruce Fields 				nlmsvc_file_inode(file)->i_sb->s_id,
607a81041b7SJ. Bruce Fields 				nlmsvc_file_inode(file)->i_ino,
6081da177e4SLinus Torvalds 				lock->fl.fl_type,
6091da177e4SLinus Torvalds 				(long long)lock->fl.fl_start,
6101da177e4SLinus Torvalds 				(long long)lock->fl.fl_end);
6111da177e4SLinus Torvalds 
6125ccb0066SStanislav Kinsbursky 	if (locks_in_grace(SVC_NET(rqstp))) {
613b2b50289SJ. Bruce Fields 		ret = nlm_lck_denied_grace_period;
614b2b50289SJ. Bruce Fields 		goto out;
615b2b50289SJ. Bruce Fields 	}
61609802fd2SJeff Layton 
6177f024fcdSJ. Bruce Fields 	mode = lock_to_openmode(&lock->fl);
6187f024fcdSJ. Bruce Fields 	error = vfs_test_lock(file->f_file[mode], &lock->fl);
6195ea0d750SMarc Eshel 	if (error) {
62009802fd2SJeff Layton 		/* We can't currently deal with deferred test requests */
62109802fd2SJeff Layton 		if (error == FILE_LOCK_DEFERRED)
62209802fd2SJeff Layton 			WARN_ON_ONCE(1);
62309802fd2SJeff Layton 
6245ea0d750SMarc Eshel 		ret = nlm_lck_denied_nolocks;
6255ea0d750SMarc Eshel 		goto out;
6265ea0d750SMarc Eshel 	}
62709802fd2SJeff Layton 
6285ea0d750SMarc Eshel 	if (lock->fl.fl_type == F_UNLCK) {
6295ea0d750SMarc Eshel 		ret = nlm_granted;
6305ea0d750SMarc Eshel 		goto out;
6315ea0d750SMarc Eshel 	}
6325ea0d750SMarc Eshel 
6331da177e4SLinus Torvalds 	dprintk("lockd: conflicting lock(ty=%d, %Ld-%Ld)\n",
6345ea0d750SMarc Eshel 		lock->fl.fl_type, (long long)lock->fl.fl_start,
6359d6a8c5cSMarc Eshel 		(long long)lock->fl.fl_end);
6361da177e4SLinus Torvalds 	conflock->caller = "somehost";	/* FIXME */
637db4e4c9aSOlaf Kirch 	conflock->len = strlen(conflock->caller);
6381da177e4SLinus Torvalds 	conflock->oh.len = 0;		/* don't return OH info */
639cd2d644dSBenjamin Coddington 	conflock->svid = lock->fl.fl_pid;
6409d6a8c5cSMarc Eshel 	conflock->fl.fl_type = lock->fl.fl_type;
6419d6a8c5cSMarc Eshel 	conflock->fl.fl_start = lock->fl.fl_start;
6429d6a8c5cSMarc Eshel 	conflock->fl.fl_end = lock->fl.fl_end;
643f328296eSKinglong Mee 	locks_release_private(&lock->fl);
64489e0edfbSBenjamin Coddington 
6455ea0d750SMarc Eshel 	ret = nlm_lck_denied;
6465ea0d750SMarc Eshel out:
6475ea0d750SMarc Eshel 	return ret;
6481da177e4SLinus Torvalds }
6491da177e4SLinus Torvalds 
6501da177e4SLinus Torvalds /*
6511da177e4SLinus Torvalds  * Remove a lock.
6521da177e4SLinus Torvalds  * This implies a CANCEL call: We send a GRANT_MSG, the client replies
6531da177e4SLinus Torvalds  * with a GRANT_RES call which gets lost, and calls UNLOCK immediately
6541da177e4SLinus Torvalds  * afterwards. In this case the block will still be there, and hence
6551da177e4SLinus Torvalds  * must be removed.
6561da177e4SLinus Torvalds  */
65752921e02SAl Viro __be32
nlmsvc_unlock(struct net * net,struct nlm_file * file,struct nlm_lock * lock)6585ccb0066SStanislav Kinsbursky nlmsvc_unlock(struct net *net, struct nlm_file *file, struct nlm_lock *lock)
6591da177e4SLinus Torvalds {
6607f024fcdSJ. Bruce Fields 	int	error = 0;
6611da177e4SLinus Torvalds 
6621da177e4SLinus Torvalds 	dprintk("lockd: nlmsvc_unlock(%s/%ld, pi=%d, %Ld-%Ld)\n",
663a81041b7SJ. Bruce Fields 				nlmsvc_file_inode(file)->i_sb->s_id,
664a81041b7SJ. Bruce Fields 				nlmsvc_file_inode(file)->i_ino,
6651da177e4SLinus Torvalds 				lock->fl.fl_pid,
6661da177e4SLinus Torvalds 				(long long)lock->fl.fl_start,
6671da177e4SLinus Torvalds 				(long long)lock->fl.fl_end);
6681da177e4SLinus Torvalds 
6691da177e4SLinus Torvalds 	/* First, cancel any lock that might be there */
6705ccb0066SStanislav Kinsbursky 	nlmsvc_cancel_blocked(net, file, lock);
6711da177e4SLinus Torvalds 
6721da177e4SLinus Torvalds 	lock->fl.fl_type = F_UNLCK;
67369efce00SJeff Layton 	lock->fl.fl_file = file->f_file[O_RDONLY];
67469efce00SJeff Layton 	if (lock->fl.fl_file)
67569efce00SJeff Layton 		error = vfs_lock_file(lock->fl.fl_file, F_SETLK,
6767f024fcdSJ. Bruce Fields 					&lock->fl, NULL);
67769efce00SJeff Layton 	lock->fl.fl_file = file->f_file[O_WRONLY];
67869efce00SJeff Layton 	if (lock->fl.fl_file)
67969efce00SJeff Layton 		error |= vfs_lock_file(lock->fl.fl_file, F_SETLK,
6807f024fcdSJ. Bruce Fields 					&lock->fl, NULL);
6811da177e4SLinus Torvalds 
6821da177e4SLinus Torvalds 	return (error < 0)? nlm_lck_denied_nolocks : nlm_granted;
6831da177e4SLinus Torvalds }
6841da177e4SLinus Torvalds 
6851da177e4SLinus Torvalds /*
6861da177e4SLinus Torvalds  * Cancel a previously blocked request.
6871da177e4SLinus Torvalds  *
6881da177e4SLinus Torvalds  * A cancel request always overrides any grant that may currently
6891da177e4SLinus Torvalds  * be in progress.
6901da177e4SLinus Torvalds  * The calling procedure must check whether the file can be closed.
6911da177e4SLinus Torvalds  */
69252921e02SAl Viro __be32
nlmsvc_cancel_blocked(struct net * net,struct nlm_file * file,struct nlm_lock * lock)6935ccb0066SStanislav Kinsbursky nlmsvc_cancel_blocked(struct net *net, struct nlm_file *file, struct nlm_lock *lock)
6941da177e4SLinus Torvalds {
6951da177e4SLinus Torvalds 	struct nlm_block	*block;
69664a318eeSJ. Bruce Fields 	int status = 0;
6977f024fcdSJ. Bruce Fields 	int mode;
6981da177e4SLinus Torvalds 
6991da177e4SLinus Torvalds 	dprintk("lockd: nlmsvc_cancel(%s/%ld, pi=%d, %Ld-%Ld)\n",
700a81041b7SJ. Bruce Fields 				nlmsvc_file_inode(file)->i_sb->s_id,
701a81041b7SJ. Bruce Fields 				nlmsvc_file_inode(file)->i_ino,
7021da177e4SLinus Torvalds 				lock->fl.fl_pid,
7031da177e4SLinus Torvalds 				(long long)lock->fl.fl_start,
7041da177e4SLinus Torvalds 				(long long)lock->fl.fl_end);
7051da177e4SLinus Torvalds 
7065ccb0066SStanislav Kinsbursky 	if (locks_in_grace(net))
707b2b50289SJ. Bruce Fields 		return nlm_lck_denied_grace_period;
708b2b50289SJ. Bruce Fields 
70989e63ef6SNeil Brown 	mutex_lock(&file->f_mutex);
710d9f6eb75STrond Myklebust 	block = nlmsvc_lookup_block(file, lock);
71189e63ef6SNeil Brown 	mutex_unlock(&file->f_mutex);
712d9f6eb75STrond Myklebust 	if (block != NULL) {
7139f27783bSJeff Layton 		struct file_lock *fl = &block->b_call->a_args.lock.fl;
7149f27783bSJeff Layton 
7159f27783bSJeff Layton 		mode = lock_to_openmode(fl);
7169f27783bSJeff Layton 		vfs_cancel_lock(block->b_file->f_file[mode], fl);
7176849c0caSTrond Myklebust 		status = nlmsvc_unlink_block(block);
7186849c0caSTrond Myklebust 		nlmsvc_release_block(block);
7196849c0caSTrond Myklebust 	}
72064a318eeSJ. Bruce Fields 	return status ? nlm_lck_denied : nlm_granted;
7211da177e4SLinus Torvalds }
7221da177e4SLinus Torvalds 
7231da177e4SLinus Torvalds /*
7240e4ac9d9SMarc Eshel  * This is a callback from the filesystem for VFS file lock requests.
7258fb47a4fSJ. Bruce Fields  * It will be used if lm_grant is defined and the filesystem can not
7260e4ac9d9SMarc Eshel  * respond to the request immediately.
7270e4ac9d9SMarc Eshel  * For SETLK or SETLKW request it will get the local posix lock.
7280e4ac9d9SMarc Eshel  * In all cases it will move the block to the head of nlm_blocked q where
7290e4ac9d9SMarc Eshel  * nlmsvc_retry_blocked() can send back a reply for SETLKW or revisit the
7300e4ac9d9SMarc Eshel  * deferred rpc for GETLK and SETLK.
7310e4ac9d9SMarc Eshel  */
7320e4ac9d9SMarc Eshel static void
nlmsvc_update_deferred_block(struct nlm_block * block,int result)733d0449b90SJoe Perches nlmsvc_update_deferred_block(struct nlm_block *block, int result)
7340e4ac9d9SMarc Eshel {
7350e4ac9d9SMarc Eshel 	block->b_flags |= B_GOT_CALLBACK;
7360e4ac9d9SMarc Eshel 	if (result == 0)
7370e4ac9d9SMarc Eshel 		block->b_granted = 1;
7380e4ac9d9SMarc Eshel 	else
7390e4ac9d9SMarc Eshel 		block->b_flags |= B_TIMED_OUT;
7400e4ac9d9SMarc Eshel }
7410e4ac9d9SMarc Eshel 
nlmsvc_grant_deferred(struct file_lock * fl,int result)742d0449b90SJoe Perches static int nlmsvc_grant_deferred(struct file_lock *fl, int result)
7430e4ac9d9SMarc Eshel {
7440e4ac9d9SMarc Eshel 	struct nlm_block *block;
7450e4ac9d9SMarc Eshel 	int rc = -ENOENT;
7460e4ac9d9SMarc Eshel 
747f904be9cSBryan Schumaker 	spin_lock(&nlm_blocked_lock);
7480e4ac9d9SMarc Eshel 	list_for_each_entry(block, &nlm_blocked, b_list) {
7490e4ac9d9SMarc Eshel 		if (nlm_compare_locks(&block->b_call->a_args.lock.fl, fl)) {
7500e4ac9d9SMarc Eshel 			dprintk("lockd: nlmsvc_notify_blocked block %p flags %d\n",
7510e4ac9d9SMarc Eshel 							block, block->b_flags);
7520e4ac9d9SMarc Eshel 			if (block->b_flags & B_QUEUED) {
7530e4ac9d9SMarc Eshel 				if (block->b_flags & B_TIMED_OUT) {
7540e4ac9d9SMarc Eshel 					rc = -ENOLCK;
7550e4ac9d9SMarc Eshel 					break;
7560e4ac9d9SMarc Eshel 				}
757d0449b90SJoe Perches 				nlmsvc_update_deferred_block(block, result);
7580e4ac9d9SMarc Eshel 			} else if (result == 0)
7590e4ac9d9SMarc Eshel 				block->b_granted = 1;
7600e4ac9d9SMarc Eshel 
761f904be9cSBryan Schumaker 			nlmsvc_insert_block_locked(block, 0);
7620e4ac9d9SMarc Eshel 			svc_wake_up(block->b_daemon);
7630e4ac9d9SMarc Eshel 			rc = 0;
7640e4ac9d9SMarc Eshel 			break;
7650e4ac9d9SMarc Eshel 		}
7660e4ac9d9SMarc Eshel 	}
767f904be9cSBryan Schumaker 	spin_unlock(&nlm_blocked_lock);
7680e4ac9d9SMarc Eshel 	if (rc == -ENOENT)
7690e4ac9d9SMarc Eshel 		printk(KERN_WARNING "lockd: grant for unknown block\n");
7700e4ac9d9SMarc Eshel 	return rc;
7710e4ac9d9SMarc Eshel }
7720e4ac9d9SMarc Eshel 
7730e4ac9d9SMarc Eshel /*
7741da177e4SLinus Torvalds  * Unblock a blocked lock request. This is a callback invoked from the
7751da177e4SLinus Torvalds  * VFS layer when a lock on which we blocked is removed.
7761da177e4SLinus Torvalds  *
7771da177e4SLinus Torvalds  * This function doesn't grant the blocked lock instantly, but rather moves
7781da177e4SLinus Torvalds  * the block to the head of nlm_blocked where it can be picked up by lockd.
7791da177e4SLinus Torvalds  */
7801da177e4SLinus Torvalds static void
nlmsvc_notify_blocked(struct file_lock * fl)7811da177e4SLinus Torvalds nlmsvc_notify_blocked(struct file_lock *fl)
7821da177e4SLinus Torvalds {
78368a2d76cSOlaf Kirch 	struct nlm_block	*block;
7841da177e4SLinus Torvalds 
7851da177e4SLinus Torvalds 	dprintk("lockd: VFS unblock notification for block %p\n", fl);
786a282a1faSJ. Bruce Fields 	spin_lock(&nlm_blocked_lock);
78768a2d76cSOlaf Kirch 	list_for_each_entry(block, &nlm_blocked, b_list) {
78892737230STrond Myklebust 		if (nlm_compare_locks(&block->b_call->a_args.lock.fl, fl)) {
789a282a1faSJ. Bruce Fields 			nlmsvc_insert_block_locked(block, 0);
790a282a1faSJ. Bruce Fields 			spin_unlock(&nlm_blocked_lock);
7911da177e4SLinus Torvalds 			svc_wake_up(block->b_daemon);
7921da177e4SLinus Torvalds 			return;
7931da177e4SLinus Torvalds 		}
7941da177e4SLinus Torvalds 	}
795a282a1faSJ. Bruce Fields 	spin_unlock(&nlm_blocked_lock);
7961da177e4SLinus Torvalds 	printk(KERN_WARNING "lockd: notification for unknown block!\n");
7971da177e4SLinus Torvalds }
7981da177e4SLinus Torvalds 
nlmsvc_get_owner(fl_owner_t owner)7997de875b2SJ. Bruce Fields static fl_owner_t nlmsvc_get_owner(fl_owner_t owner)
8007de875b2SJ. Bruce Fields {
8017de875b2SJ. Bruce Fields 	return nlmsvc_get_lockowner(owner);
8027de875b2SJ. Bruce Fields }
8037de875b2SJ. Bruce Fields 
nlmsvc_put_owner(fl_owner_t owner)8047de875b2SJ. Bruce Fields static void nlmsvc_put_owner(fl_owner_t owner)
8057de875b2SJ. Bruce Fields {
8067de875b2SJ. Bruce Fields 	nlmsvc_put_lockowner(owner);
8077de875b2SJ. Bruce Fields }
8087de875b2SJ. Bruce Fields 
8097b021967SAlexey Dobriyan const struct lock_manager_operations nlmsvc_lock_operations = {
8108fb47a4fSJ. Bruce Fields 	.lm_notify = nlmsvc_notify_blocked,
8118fb47a4fSJ. Bruce Fields 	.lm_grant = nlmsvc_grant_deferred,
8127de875b2SJ. Bruce Fields 	.lm_get_owner = nlmsvc_get_owner,
8137de875b2SJ. Bruce Fields 	.lm_put_owner = nlmsvc_put_owner,
8141da177e4SLinus Torvalds };
8151da177e4SLinus Torvalds 
8161da177e4SLinus Torvalds /*
8171da177e4SLinus Torvalds  * Try to claim a lock that was previously blocked.
8181da177e4SLinus Torvalds  *
8191da177e4SLinus Torvalds  * Note that we use both the RPC_GRANTED_MSG call _and_ an async
8201da177e4SLinus Torvalds  * RPC thread when notifying the client. This seems like overkill...
8211da177e4SLinus Torvalds  * Here's why:
8221da177e4SLinus Torvalds  *  -	we don't want to use a synchronous RPC thread, otherwise
8231da177e4SLinus Torvalds  *	we might find ourselves hanging on a dead portmapper.
8241da177e4SLinus Torvalds  *  -	Some lockd implementations (e.g. HP) don't react to
8251da177e4SLinus Torvalds  *	RPC_GRANTED calls; they seem to insist on RPC_GRANTED_MSG calls.
8261da177e4SLinus Torvalds  */
8271da177e4SLinus Torvalds static void
nlmsvc_grant_blocked(struct nlm_block * block)8281da177e4SLinus Torvalds nlmsvc_grant_blocked(struct nlm_block *block)
8291da177e4SLinus Torvalds {
8301da177e4SLinus Torvalds 	struct nlm_file		*file = block->b_file;
83192737230STrond Myklebust 	struct nlm_lock		*lock = &block->b_call->a_args.lock;
8327f024fcdSJ. Bruce Fields 	int			mode;
8331da177e4SLinus Torvalds 	int			error;
8342ec197dbSNeilBrown 	loff_t			fl_start, fl_end;
8351da177e4SLinus Torvalds 
8361da177e4SLinus Torvalds 	dprintk("lockd: grant blocked lock %p\n", block);
8371da177e4SLinus Torvalds 
8380e4ac9d9SMarc Eshel 	kref_get(&block->b_count);
8390e4ac9d9SMarc Eshel 
8401da177e4SLinus Torvalds 	/* Unlink block request from list */
8416849c0caSTrond Myklebust 	nlmsvc_unlink_block(block);
8421da177e4SLinus Torvalds 
8431da177e4SLinus Torvalds 	/* If b_granted is true this means we've been here before.
8441da177e4SLinus Torvalds 	 * Just retry the grant callback, possibly refreshing the RPC
8451da177e4SLinus Torvalds 	 * binding */
8461da177e4SLinus Torvalds 	if (block->b_granted) {
8471da177e4SLinus Torvalds 		nlm_rebind_host(block->b_host);
8481da177e4SLinus Torvalds 		goto callback;
8491da177e4SLinus Torvalds 	}
8501da177e4SLinus Torvalds 
8511da177e4SLinus Torvalds 	/* Try the lock operation again */
8522ec197dbSNeilBrown 	/* vfs_lock_file() can mangle fl_start and fl_end, but we need
8532ec197dbSNeilBrown 	 * them unchanged for the GRANT_MSG
8542ec197dbSNeilBrown 	 */
85509c7938cSTrond Myklebust 	lock->fl.fl_flags |= FL_SLEEP;
8562ec197dbSNeilBrown 	fl_start = lock->fl.fl_start;
8572ec197dbSNeilBrown 	fl_end = lock->fl.fl_end;
8587f024fcdSJ. Bruce Fields 	mode = lock_to_openmode(&lock->fl);
8597f024fcdSJ. Bruce Fields 	error = vfs_lock_file(file->f_file[mode], F_SETLK, &lock->fl, NULL);
86009c7938cSTrond Myklebust 	lock->fl.fl_flags &= ~FL_SLEEP;
8612ec197dbSNeilBrown 	lock->fl.fl_start = fl_start;
8622ec197dbSNeilBrown 	lock->fl.fl_end = fl_end;
86309c7938cSTrond Myklebust 
8645de0e502SAndy Adamson 	switch (error) {
8655de0e502SAndy Adamson 	case 0:
8665de0e502SAndy Adamson 		break;
867bde74e4bSMiklos Szeredi 	case FILE_LOCK_DEFERRED:
8681a8322b2SMarc Eshel 		dprintk("lockd: lock still blocked error %d\n", error);
8691da177e4SLinus Torvalds 		nlmsvc_insert_block(block, NLM_NEVER);
8700e4ac9d9SMarc Eshel 		nlmsvc_release_block(block);
871d9f6eb75STrond Myklebust 		return;
8725de0e502SAndy Adamson 	default:
8731da177e4SLinus Torvalds 		printk(KERN_WARNING "lockd: unexpected error %d in %s!\n",
8748e24eea7SHarvey Harrison 				-error, __func__);
8751da177e4SLinus Torvalds 		nlmsvc_insert_block(block, 10 * HZ);
8760e4ac9d9SMarc Eshel 		nlmsvc_release_block(block);
877d9f6eb75STrond Myklebust 		return;
8781da177e4SLinus Torvalds 	}
8791da177e4SLinus Torvalds 
8801da177e4SLinus Torvalds callback:
8811da177e4SLinus Torvalds 	/* Lock was granted by VFS. */
8821da177e4SLinus Torvalds 	dprintk("lockd: GRANTing blocked lock.\n");
8831da177e4SLinus Torvalds 	block->b_granted = 1;
8841da177e4SLinus Torvalds 
8859706501eSJeff Layton 	/* keep block on the list, but don't reattempt until the RPC
8869706501eSJeff Layton 	 * completes or the submission fails
8879706501eSJeff Layton 	 */
8889706501eSJeff Layton 	nlmsvc_insert_block(block, NLM_NEVER);
8891da177e4SLinus Torvalds 
8909706501eSJeff Layton 	/* Call the client -- use a soft RPC task since nlmsvc_retry_blocked
8919706501eSJeff Layton 	 * will queue up a new one if this one times out
8929706501eSJeff Layton 	 */
8939706501eSJeff Layton 	error = nlm_async_call(block->b_call, NLMPROC_GRANTED_MSG,
8949706501eSJeff Layton 				&nlmsvc_grant_ops);
8959706501eSJeff Layton 
8969706501eSJeff Layton 	/* RPC submission failed, wait a bit and retry */
8979706501eSJeff Layton 	if (error < 0)
8989706501eSJeff Layton 		nlmsvc_insert_block(block, 10 * HZ);
8991da177e4SLinus Torvalds }
9001da177e4SLinus Torvalds 
9011da177e4SLinus Torvalds /*
9021da177e4SLinus Torvalds  * This is the callback from the RPC layer when the NLM_GRANTED_MSG
9031da177e4SLinus Torvalds  * RPC call has succeeded or timed out.
9041da177e4SLinus Torvalds  * Like all RPC callbacks, it is invoked by the rpciod process, so it
9051da177e4SLinus Torvalds  * better not sleep. Therefore, we put the blocked lock on the nlm_blocked
9061da177e4SLinus Torvalds  * chain once more in order to have it removed by lockd itself (which can
9071da177e4SLinus Torvalds  * then sleep on the file semaphore without disrupting e.g. the nfs client).
9081da177e4SLinus Torvalds  */
nlmsvc_grant_callback(struct rpc_task * task,void * data)909963d8fe5STrond Myklebust static void nlmsvc_grant_callback(struct rpc_task *task, void *data)
9101da177e4SLinus Torvalds {
911963d8fe5STrond Myklebust 	struct nlm_rqst		*call = data;
91292737230STrond Myklebust 	struct nlm_block	*block = call->a_block;
9131da177e4SLinus Torvalds 	unsigned long		timeout;
9141da177e4SLinus Torvalds 
9151da177e4SLinus Torvalds 	dprintk("lockd: GRANT_MSG RPC callback\n");
9161da177e4SLinus Torvalds 
917f904be9cSBryan Schumaker 	spin_lock(&nlm_blocked_lock);
918c64e80d5SJeff Layton 	/* if the block is not on a list at this point then it has
919c64e80d5SJeff Layton 	 * been invalidated. Don't try to requeue it.
920c64e80d5SJeff Layton 	 *
921c64e80d5SJeff Layton 	 * FIXME: it's possible that the block is removed from the list
922c64e80d5SJeff Layton 	 * after this check but before the nlmsvc_insert_block. In that
923c64e80d5SJeff Layton 	 * case it will be added back. Perhaps we need better locking
924c64e80d5SJeff Layton 	 * for nlm_blocked?
925c64e80d5SJeff Layton 	 */
926c64e80d5SJeff Layton 	if (list_empty(&block->b_list))
927a86dc496STrond Myklebust 		goto out;
928c64e80d5SJeff Layton 
9291da177e4SLinus Torvalds 	/* Technically, we should down the file semaphore here. Since we
9301da177e4SLinus Torvalds 	 * move the block towards the head of the queue only, no harm
9311da177e4SLinus Torvalds 	 * can be done, though. */
9321da177e4SLinus Torvalds 	if (task->tk_status < 0) {
9331da177e4SLinus Torvalds 		/* RPC error: Re-insert for retransmission */
9341da177e4SLinus Torvalds 		timeout = 10 * HZ;
9351da177e4SLinus Torvalds 	} else {
9361da177e4SLinus Torvalds 		/* Call was successful, now wait for client callback */
9371da177e4SLinus Torvalds 		timeout = 60 * HZ;
9381da177e4SLinus Torvalds 	}
939f904be9cSBryan Schumaker 	nlmsvc_insert_block_locked(block, timeout);
9401da177e4SLinus Torvalds 	svc_wake_up(block->b_daemon);
941a86dc496STrond Myklebust out:
942f904be9cSBryan Schumaker 	spin_unlock(&nlm_blocked_lock);
9435e1abf8cSTrond Myklebust }
9445e1abf8cSTrond Myklebust 
945f904be9cSBryan Schumaker /*
946f904be9cSBryan Schumaker  * FIXME: nlmsvc_release_block() grabs a mutex.  This is not allowed for an
947f904be9cSBryan Schumaker  * .rpc_release rpc_call_op
948f904be9cSBryan Schumaker  */
nlmsvc_grant_release(void * data)949ec535ce1SAdrian Bunk static void nlmsvc_grant_release(void *data)
9505e1abf8cSTrond Myklebust {
9516041b791STrond Myklebust 	struct nlm_rqst		*call = data;
9526041b791STrond Myklebust 	nlmsvc_release_block(call->a_block);
9531da177e4SLinus Torvalds }
9541da177e4SLinus Torvalds 
955963d8fe5STrond Myklebust static const struct rpc_call_ops nlmsvc_grant_ops = {
956963d8fe5STrond Myklebust 	.rpc_call_done = nlmsvc_grant_callback,
9575e1abf8cSTrond Myklebust 	.rpc_release = nlmsvc_grant_release,
958963d8fe5STrond Myklebust };
959963d8fe5STrond Myklebust 
9601da177e4SLinus Torvalds /*
9611da177e4SLinus Torvalds  * We received a GRANT_RES callback. Try to find the corresponding
9621da177e4SLinus Torvalds  * block.
9631da177e4SLinus Torvalds  */
9641da177e4SLinus Torvalds void
nlmsvc_grant_reply(struct nlm_cookie * cookie,__be32 status)965e8c5c045SAl Viro nlmsvc_grant_reply(struct nlm_cookie *cookie, __be32 status)
9661da177e4SLinus Torvalds {
9671da177e4SLinus Torvalds 	struct nlm_block	*block;
968244cc191SJeff Layton 	struct file_lock	*fl;
969244cc191SJeff Layton 	int			error;
9701da177e4SLinus Torvalds 
97139be4502SOlaf Kirch 	dprintk("grant_reply: looking for cookie %x, s=%d \n",
97239be4502SOlaf Kirch 		*(unsigned int *)(cookie->data), status);
97339be4502SOlaf Kirch 	if (!(block = nlmsvc_find_block(cookie)))
9741da177e4SLinus Torvalds 		return;
9751da177e4SLinus Torvalds 
976244cc191SJeff Layton 	switch (status) {
977244cc191SJeff Layton 	case nlm_lck_denied_grace_period:
9781da177e4SLinus Torvalds 		/* Try again in a couple of seconds */
9791da177e4SLinus Torvalds 		nlmsvc_insert_block(block, 10 * HZ);
980244cc191SJeff Layton 		break;
981244cc191SJeff Layton 	case nlm_lck_denied:
982244cc191SJeff Layton 		/* Client doesn't want it, just unlock it */
983244cc191SJeff Layton 		nlmsvc_unlink_block(block);
984244cc191SJeff Layton 		fl = &block->b_call->a_args.lock.fl;
985244cc191SJeff Layton 		fl->fl_type = F_UNLCK;
986244cc191SJeff Layton 		error = vfs_lock_file(fl->fl_file, F_SETLK, fl, NULL);
987244cc191SJeff Layton 		if (error)
988244cc191SJeff Layton 			pr_warn("lockd: unable to unlock lock rejected by client!\n");
989244cc191SJeff Layton 		break;
990244cc191SJeff Layton 	default:
991e56efe93SColin Ian King 		/*
992244cc191SJeff Layton 		 * Either it was accepted or the status makes no sense
993244cc191SJeff Layton 		 * just unlink it either way.
994e56efe93SColin Ian King 		 */
9956849c0caSTrond Myklebust 		nlmsvc_unlink_block(block);
9966849c0caSTrond Myklebust 	}
9976849c0caSTrond Myklebust 	nlmsvc_release_block(block);
9981da177e4SLinus Torvalds }
9991da177e4SLinus Torvalds 
10000e4ac9d9SMarc Eshel /* Helper function to handle retry of a deferred block.
10010e4ac9d9SMarc Eshel  * If it is a blocking lock, call grant_blocked.
10020e4ac9d9SMarc Eshel  * For a non-blocking lock or test lock, revisit the request.
10030e4ac9d9SMarc Eshel  */
10040e4ac9d9SMarc Eshel static void
retry_deferred_block(struct nlm_block * block)10050e4ac9d9SMarc Eshel retry_deferred_block(struct nlm_block *block)
10060e4ac9d9SMarc Eshel {
10070e4ac9d9SMarc Eshel 	if (!(block->b_flags & B_GOT_CALLBACK))
10080e4ac9d9SMarc Eshel 		block->b_flags |= B_TIMED_OUT;
10090e4ac9d9SMarc Eshel 	nlmsvc_insert_block(block, NLM_TIMEOUT);
10100e4ac9d9SMarc Eshel 	dprintk("revisit block %p flags %d\n",	block, block->b_flags);
10110e4ac9d9SMarc Eshel 	if (block->b_deferred_req) {
10120e4ac9d9SMarc Eshel 		block->b_deferred_req->revisit(block->b_deferred_req, 0);
10130e4ac9d9SMarc Eshel 		block->b_deferred_req = NULL;
10140e4ac9d9SMarc Eshel 	}
10150e4ac9d9SMarc Eshel }
10160e4ac9d9SMarc Eshel 
10171da177e4SLinus Torvalds /*
10181da177e4SLinus Torvalds  * Retry all blocked locks that have been notified. This is where lockd
10191da177e4SLinus Torvalds  * picks up locks that can be granted, or grant notifications that must
10201da177e4SLinus Torvalds  * be retransmitted.
10211da177e4SLinus Torvalds  */
1022*c743b425SNeilBrown void
nlmsvc_retry_blocked(void)10231da177e4SLinus Torvalds nlmsvc_retry_blocked(void)
10241da177e4SLinus Torvalds {
102568a2d76cSOlaf Kirch 	unsigned long	timeout = MAX_SCHEDULE_TIMEOUT;
10261da177e4SLinus Torvalds 	struct nlm_block *block;
10271da177e4SLinus Torvalds 
10281c327d96SDavid Jeffery 	spin_lock(&nlm_blocked_lock);
1029d751a7cdSJeff Layton 	while (!list_empty(&nlm_blocked) && !kthread_should_stop()) {
103068a2d76cSOlaf Kirch 		block = list_entry(nlm_blocked.next, struct nlm_block, b_list);
103168a2d76cSOlaf Kirch 
10321da177e4SLinus Torvalds 		if (block->b_when == NLM_NEVER)
10331da177e4SLinus Torvalds 			break;
103468a2d76cSOlaf Kirch 		if (time_after(block->b_when, jiffies)) {
103568a2d76cSOlaf Kirch 			timeout = block->b_when - jiffies;
10361da177e4SLinus Torvalds 			break;
103768a2d76cSOlaf Kirch 		}
10381c327d96SDavid Jeffery 		spin_unlock(&nlm_blocked_lock);
103968a2d76cSOlaf Kirch 
1040f3d43c76SJ. Bruce Fields 		dprintk("nlmsvc_retry_blocked(%p, when=%ld)\n",
1041f3d43c76SJ. Bruce Fields 			block, block->b_when);
10420e4ac9d9SMarc Eshel 		if (block->b_flags & B_QUEUED) {
10430e4ac9d9SMarc Eshel 			dprintk("nlmsvc_retry_blocked delete block (%p, granted=%d, flags=%d)\n",
10440e4ac9d9SMarc Eshel 				block, block->b_granted, block->b_flags);
10450e4ac9d9SMarc Eshel 			retry_deferred_block(block);
10460e4ac9d9SMarc Eshel 		} else
10471da177e4SLinus Torvalds 			nlmsvc_grant_blocked(block);
10481c327d96SDavid Jeffery 		spin_lock(&nlm_blocked_lock);
10491da177e4SLinus Torvalds 	}
10501c327d96SDavid Jeffery 	spin_unlock(&nlm_blocked_lock);
10511da177e4SLinus Torvalds 
1052*c743b425SNeilBrown 	if (timeout < MAX_SCHEDULE_TIMEOUT)
1053*c743b425SNeilBrown 		mod_timer(&nlmsvc_retry, jiffies + timeout);
10541da177e4SLinus Torvalds }
1055