18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * linux/fs/lockd/svcsubs.c
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Various support routines for the NLM server.
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/types.h>
118c2ecf20Sopenharmony_ci#include <linux/string.h>
128c2ecf20Sopenharmony_ci#include <linux/time.h>
138c2ecf20Sopenharmony_ci#include <linux/in.h>
148c2ecf20Sopenharmony_ci#include <linux/slab.h>
158c2ecf20Sopenharmony_ci#include <linux/mutex.h>
168c2ecf20Sopenharmony_ci#include <linux/sunrpc/svc.h>
178c2ecf20Sopenharmony_ci#include <linux/sunrpc/addr.h>
188c2ecf20Sopenharmony_ci#include <linux/lockd/lockd.h>
198c2ecf20Sopenharmony_ci#include <linux/lockd/share.h>
208c2ecf20Sopenharmony_ci#include <linux/module.h>
218c2ecf20Sopenharmony_ci#include <linux/mount.h>
228c2ecf20Sopenharmony_ci#include <uapi/linux/nfs2.h>
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#define NLMDBG_FACILITY		NLMDBG_SVCSUBS
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci/*
288c2ecf20Sopenharmony_ci * Global file hash table
298c2ecf20Sopenharmony_ci */
308c2ecf20Sopenharmony_ci#define FILE_HASH_BITS		7
318c2ecf20Sopenharmony_ci#define FILE_NRHASH		(1<<FILE_HASH_BITS)
328c2ecf20Sopenharmony_cistatic struct hlist_head	nlm_files[FILE_NRHASH];
338c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(nlm_file_mutex);
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci#ifdef CONFIG_SUNRPC_DEBUG
368c2ecf20Sopenharmony_cistatic inline void nlm_debug_print_fh(char *msg, struct nfs_fh *f)
378c2ecf20Sopenharmony_ci{
388c2ecf20Sopenharmony_ci	u32 *fhp = (u32*)f->data;
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	/* print the first 32 bytes of the fh */
418c2ecf20Sopenharmony_ci	dprintk("lockd: %s (%08x %08x %08x %08x %08x %08x %08x %08x)\n",
428c2ecf20Sopenharmony_ci		msg, fhp[0], fhp[1], fhp[2], fhp[3],
438c2ecf20Sopenharmony_ci		fhp[4], fhp[5], fhp[6], fhp[7]);
448c2ecf20Sopenharmony_ci}
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_cistatic inline void nlm_debug_print_file(char *msg, struct nlm_file *file)
478c2ecf20Sopenharmony_ci{
488c2ecf20Sopenharmony_ci	struct inode *inode = locks_inode(file->f_file);
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci	dprintk("lockd: %s %s/%ld\n",
518c2ecf20Sopenharmony_ci		msg, inode->i_sb->s_id, inode->i_ino);
528c2ecf20Sopenharmony_ci}
538c2ecf20Sopenharmony_ci#else
548c2ecf20Sopenharmony_cistatic inline void nlm_debug_print_fh(char *msg, struct nfs_fh *f)
558c2ecf20Sopenharmony_ci{
568c2ecf20Sopenharmony_ci	return;
578c2ecf20Sopenharmony_ci}
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_cistatic inline void nlm_debug_print_file(char *msg, struct nlm_file *file)
608c2ecf20Sopenharmony_ci{
618c2ecf20Sopenharmony_ci	return;
628c2ecf20Sopenharmony_ci}
638c2ecf20Sopenharmony_ci#endif
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_cistatic inline unsigned int file_hash(struct nfs_fh *f)
668c2ecf20Sopenharmony_ci{
678c2ecf20Sopenharmony_ci	unsigned int tmp=0;
688c2ecf20Sopenharmony_ci	int i;
698c2ecf20Sopenharmony_ci	for (i=0; i<NFS2_FHSIZE;i++)
708c2ecf20Sopenharmony_ci		tmp += f->data[i];
718c2ecf20Sopenharmony_ci	return tmp & (FILE_NRHASH - 1);
728c2ecf20Sopenharmony_ci}
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci/*
758c2ecf20Sopenharmony_ci * Lookup file info. If it doesn't exist, create a file info struct
768c2ecf20Sopenharmony_ci * and open a (VFS) file for the given inode.
778c2ecf20Sopenharmony_ci *
788c2ecf20Sopenharmony_ci * FIXME:
798c2ecf20Sopenharmony_ci * Note that we open the file O_RDONLY even when creating write locks.
808c2ecf20Sopenharmony_ci * This is not quite right, but for now, we assume the client performs
818c2ecf20Sopenharmony_ci * the proper R/W checking.
828c2ecf20Sopenharmony_ci */
838c2ecf20Sopenharmony_ci__be32
848c2ecf20Sopenharmony_cinlm_lookup_file(struct svc_rqst *rqstp, struct nlm_file **result,
858c2ecf20Sopenharmony_ci					struct nfs_fh *f)
868c2ecf20Sopenharmony_ci{
878c2ecf20Sopenharmony_ci	struct nlm_file	*file;
888c2ecf20Sopenharmony_ci	unsigned int	hash;
898c2ecf20Sopenharmony_ci	__be32		nfserr;
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	nlm_debug_print_fh("nlm_lookup_file", f);
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	hash = file_hash(f);
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	/* Lock file table */
968c2ecf20Sopenharmony_ci	mutex_lock(&nlm_file_mutex);
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	hlist_for_each_entry(file, &nlm_files[hash], f_list)
998c2ecf20Sopenharmony_ci		if (!nfs_compare_fh(&file->f_handle, f))
1008c2ecf20Sopenharmony_ci			goto found;
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci	nlm_debug_print_fh("creating file for", f);
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	nfserr = nlm_lck_denied_nolocks;
1058c2ecf20Sopenharmony_ci	file = kzalloc(sizeof(*file), GFP_KERNEL);
1068c2ecf20Sopenharmony_ci	if (!file)
1078c2ecf20Sopenharmony_ci		goto out_unlock;
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	memcpy(&file->f_handle, f, sizeof(struct nfs_fh));
1108c2ecf20Sopenharmony_ci	mutex_init(&file->f_mutex);
1118c2ecf20Sopenharmony_ci	INIT_HLIST_NODE(&file->f_list);
1128c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&file->f_blocks);
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	/* Open the file. Note that this must not sleep for too long, else
1158c2ecf20Sopenharmony_ci	 * we would lock up lockd:-) So no NFS re-exports, folks.
1168c2ecf20Sopenharmony_ci	 *
1178c2ecf20Sopenharmony_ci	 * We have to make sure we have the right credential to open
1188c2ecf20Sopenharmony_ci	 * the file.
1198c2ecf20Sopenharmony_ci	 */
1208c2ecf20Sopenharmony_ci	if ((nfserr = nlmsvc_ops->fopen(rqstp, f, &file->f_file)) != 0) {
1218c2ecf20Sopenharmony_ci		dprintk("lockd: open failed (error %d)\n", nfserr);
1228c2ecf20Sopenharmony_ci		goto out_free;
1238c2ecf20Sopenharmony_ci	}
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	hlist_add_head(&file->f_list, &nlm_files[hash]);
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_cifound:
1288c2ecf20Sopenharmony_ci	dprintk("lockd: found file %p (count %d)\n", file, file->f_count);
1298c2ecf20Sopenharmony_ci	*result = file;
1308c2ecf20Sopenharmony_ci	file->f_count++;
1318c2ecf20Sopenharmony_ci	nfserr = 0;
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ciout_unlock:
1348c2ecf20Sopenharmony_ci	mutex_unlock(&nlm_file_mutex);
1358c2ecf20Sopenharmony_ci	return nfserr;
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ciout_free:
1388c2ecf20Sopenharmony_ci	kfree(file);
1398c2ecf20Sopenharmony_ci	goto out_unlock;
1408c2ecf20Sopenharmony_ci}
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci/*
1438c2ecf20Sopenharmony_ci * Delete a file after having released all locks, blocks and shares
1448c2ecf20Sopenharmony_ci */
1458c2ecf20Sopenharmony_cistatic inline void
1468c2ecf20Sopenharmony_cinlm_delete_file(struct nlm_file *file)
1478c2ecf20Sopenharmony_ci{
1488c2ecf20Sopenharmony_ci	nlm_debug_print_file("closing file", file);
1498c2ecf20Sopenharmony_ci	if (!hlist_unhashed(&file->f_list)) {
1508c2ecf20Sopenharmony_ci		hlist_del(&file->f_list);
1518c2ecf20Sopenharmony_ci		nlmsvc_ops->fclose(file->f_file);
1528c2ecf20Sopenharmony_ci		kfree(file);
1538c2ecf20Sopenharmony_ci	} else {
1548c2ecf20Sopenharmony_ci		printk(KERN_WARNING "lockd: attempt to release unknown file!\n");
1558c2ecf20Sopenharmony_ci	}
1568c2ecf20Sopenharmony_ci}
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci/*
1598c2ecf20Sopenharmony_ci * Loop over all locks on the given file and perform the specified
1608c2ecf20Sopenharmony_ci * action.
1618c2ecf20Sopenharmony_ci */
1628c2ecf20Sopenharmony_cistatic int
1638c2ecf20Sopenharmony_cinlm_traverse_locks(struct nlm_host *host, struct nlm_file *file,
1648c2ecf20Sopenharmony_ci			nlm_host_match_fn_t match)
1658c2ecf20Sopenharmony_ci{
1668c2ecf20Sopenharmony_ci	struct inode	 *inode = nlmsvc_file_inode(file);
1678c2ecf20Sopenharmony_ci	struct file_lock *fl;
1688c2ecf20Sopenharmony_ci	struct file_lock_context *flctx = inode->i_flctx;
1698c2ecf20Sopenharmony_ci	struct nlm_host	 *lockhost;
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	if (!flctx || list_empty_careful(&flctx->flc_posix))
1728c2ecf20Sopenharmony_ci		return 0;
1738c2ecf20Sopenharmony_ciagain:
1748c2ecf20Sopenharmony_ci	file->f_locks = 0;
1758c2ecf20Sopenharmony_ci	spin_lock(&flctx->flc_lock);
1768c2ecf20Sopenharmony_ci	list_for_each_entry(fl, &flctx->flc_posix, fl_list) {
1778c2ecf20Sopenharmony_ci		if (fl->fl_lmops != &nlmsvc_lock_operations)
1788c2ecf20Sopenharmony_ci			continue;
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci		/* update current lock count */
1818c2ecf20Sopenharmony_ci		file->f_locks++;
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci		lockhost = ((struct nlm_lockowner *)fl->fl_owner)->host;
1848c2ecf20Sopenharmony_ci		if (match(lockhost, host)) {
1858c2ecf20Sopenharmony_ci			struct file_lock lock = *fl;
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci			spin_unlock(&flctx->flc_lock);
1888c2ecf20Sopenharmony_ci			lock.fl_type  = F_UNLCK;
1898c2ecf20Sopenharmony_ci			lock.fl_start = 0;
1908c2ecf20Sopenharmony_ci			lock.fl_end   = OFFSET_MAX;
1918c2ecf20Sopenharmony_ci			if (vfs_lock_file(file->f_file, F_SETLK, &lock, NULL) < 0) {
1928c2ecf20Sopenharmony_ci				printk("lockd: unlock failure in %s:%d\n",
1938c2ecf20Sopenharmony_ci						__FILE__, __LINE__);
1948c2ecf20Sopenharmony_ci				return 1;
1958c2ecf20Sopenharmony_ci			}
1968c2ecf20Sopenharmony_ci			goto again;
1978c2ecf20Sopenharmony_ci		}
1988c2ecf20Sopenharmony_ci	}
1998c2ecf20Sopenharmony_ci	spin_unlock(&flctx->flc_lock);
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	return 0;
2028c2ecf20Sopenharmony_ci}
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_cistatic int
2058c2ecf20Sopenharmony_cinlmsvc_always_match(void *dummy1, struct nlm_host *dummy2)
2068c2ecf20Sopenharmony_ci{
2078c2ecf20Sopenharmony_ci	return 1;
2088c2ecf20Sopenharmony_ci}
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci/*
2118c2ecf20Sopenharmony_ci * Inspect a single file
2128c2ecf20Sopenharmony_ci */
2138c2ecf20Sopenharmony_cistatic inline int
2148c2ecf20Sopenharmony_cinlm_inspect_file(struct nlm_host *host, struct nlm_file *file, nlm_host_match_fn_t match)
2158c2ecf20Sopenharmony_ci{
2168c2ecf20Sopenharmony_ci	nlmsvc_traverse_blocks(host, file, match);
2178c2ecf20Sopenharmony_ci	nlmsvc_traverse_shares(host, file, match);
2188c2ecf20Sopenharmony_ci	return nlm_traverse_locks(host, file, match);
2198c2ecf20Sopenharmony_ci}
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci/*
2228c2ecf20Sopenharmony_ci * Quick check whether there are still any locks, blocks or
2238c2ecf20Sopenharmony_ci * shares on a given file.
2248c2ecf20Sopenharmony_ci */
2258c2ecf20Sopenharmony_cistatic inline int
2268c2ecf20Sopenharmony_cinlm_file_inuse(struct nlm_file *file)
2278c2ecf20Sopenharmony_ci{
2288c2ecf20Sopenharmony_ci	struct inode	 *inode = nlmsvc_file_inode(file);
2298c2ecf20Sopenharmony_ci	struct file_lock *fl;
2308c2ecf20Sopenharmony_ci	struct file_lock_context *flctx = inode->i_flctx;
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	if (file->f_count || !list_empty(&file->f_blocks) || file->f_shares)
2338c2ecf20Sopenharmony_ci		return 1;
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	if (flctx && !list_empty_careful(&flctx->flc_posix)) {
2368c2ecf20Sopenharmony_ci		spin_lock(&flctx->flc_lock);
2378c2ecf20Sopenharmony_ci		list_for_each_entry(fl, &flctx->flc_posix, fl_list) {
2388c2ecf20Sopenharmony_ci			if (fl->fl_lmops == &nlmsvc_lock_operations) {
2398c2ecf20Sopenharmony_ci				spin_unlock(&flctx->flc_lock);
2408c2ecf20Sopenharmony_ci				return 1;
2418c2ecf20Sopenharmony_ci			}
2428c2ecf20Sopenharmony_ci		}
2438c2ecf20Sopenharmony_ci		spin_unlock(&flctx->flc_lock);
2448c2ecf20Sopenharmony_ci	}
2458c2ecf20Sopenharmony_ci	file->f_locks = 0;
2468c2ecf20Sopenharmony_ci	return 0;
2478c2ecf20Sopenharmony_ci}
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci/*
2508c2ecf20Sopenharmony_ci * Loop over all files in the file table.
2518c2ecf20Sopenharmony_ci */
2528c2ecf20Sopenharmony_cistatic int
2538c2ecf20Sopenharmony_cinlm_traverse_files(void *data, nlm_host_match_fn_t match,
2548c2ecf20Sopenharmony_ci		int (*is_failover_file)(void *data, struct nlm_file *file))
2558c2ecf20Sopenharmony_ci{
2568c2ecf20Sopenharmony_ci	struct hlist_node *next;
2578c2ecf20Sopenharmony_ci	struct nlm_file	*file;
2588c2ecf20Sopenharmony_ci	int i, ret = 0;
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci	mutex_lock(&nlm_file_mutex);
2618c2ecf20Sopenharmony_ci	for (i = 0; i < FILE_NRHASH; i++) {
2628c2ecf20Sopenharmony_ci		hlist_for_each_entry_safe(file, next, &nlm_files[i], f_list) {
2638c2ecf20Sopenharmony_ci			if (is_failover_file && !is_failover_file(data, file))
2648c2ecf20Sopenharmony_ci				continue;
2658c2ecf20Sopenharmony_ci			file->f_count++;
2668c2ecf20Sopenharmony_ci			mutex_unlock(&nlm_file_mutex);
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci			/* Traverse locks, blocks and shares of this file
2698c2ecf20Sopenharmony_ci			 * and update file->f_locks count */
2708c2ecf20Sopenharmony_ci			if (nlm_inspect_file(data, file, match))
2718c2ecf20Sopenharmony_ci				ret = 1;
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci			mutex_lock(&nlm_file_mutex);
2748c2ecf20Sopenharmony_ci			file->f_count--;
2758c2ecf20Sopenharmony_ci			/* No more references to this file. Let go of it. */
2768c2ecf20Sopenharmony_ci			if (list_empty(&file->f_blocks) && !file->f_locks
2778c2ecf20Sopenharmony_ci			 && !file->f_shares && !file->f_count) {
2788c2ecf20Sopenharmony_ci				hlist_del(&file->f_list);
2798c2ecf20Sopenharmony_ci				nlmsvc_ops->fclose(file->f_file);
2808c2ecf20Sopenharmony_ci				kfree(file);
2818c2ecf20Sopenharmony_ci			}
2828c2ecf20Sopenharmony_ci		}
2838c2ecf20Sopenharmony_ci	}
2848c2ecf20Sopenharmony_ci	mutex_unlock(&nlm_file_mutex);
2858c2ecf20Sopenharmony_ci	return ret;
2868c2ecf20Sopenharmony_ci}
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci/*
2898c2ecf20Sopenharmony_ci * Release file. If there are no more remote locks on this file,
2908c2ecf20Sopenharmony_ci * close it and free the handle.
2918c2ecf20Sopenharmony_ci *
2928c2ecf20Sopenharmony_ci * Note that we can't do proper reference counting without major
2938c2ecf20Sopenharmony_ci * contortions because the code in fs/locks.c creates, deletes and
2948c2ecf20Sopenharmony_ci * splits locks without notification. Our only way is to walk the
2958c2ecf20Sopenharmony_ci * entire lock list each time we remove a lock.
2968c2ecf20Sopenharmony_ci */
2978c2ecf20Sopenharmony_civoid
2988c2ecf20Sopenharmony_cinlm_release_file(struct nlm_file *file)
2998c2ecf20Sopenharmony_ci{
3008c2ecf20Sopenharmony_ci	dprintk("lockd: nlm_release_file(%p, ct = %d)\n",
3018c2ecf20Sopenharmony_ci				file, file->f_count);
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	/* Lock file table */
3048c2ecf20Sopenharmony_ci	mutex_lock(&nlm_file_mutex);
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci	/* If there are no more locks etc, delete the file */
3078c2ecf20Sopenharmony_ci	if (--file->f_count == 0 && !nlm_file_inuse(file))
3088c2ecf20Sopenharmony_ci		nlm_delete_file(file);
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci	mutex_unlock(&nlm_file_mutex);
3118c2ecf20Sopenharmony_ci}
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci/*
3148c2ecf20Sopenharmony_ci * Helpers function for resource traversal
3158c2ecf20Sopenharmony_ci *
3168c2ecf20Sopenharmony_ci * nlmsvc_mark_host:
3178c2ecf20Sopenharmony_ci *	used by the garbage collector; simply sets h_inuse only for those
3188c2ecf20Sopenharmony_ci *	hosts, which passed network check.
3198c2ecf20Sopenharmony_ci *	Always returns 0.
3208c2ecf20Sopenharmony_ci *
3218c2ecf20Sopenharmony_ci * nlmsvc_same_host:
3228c2ecf20Sopenharmony_ci *	returns 1 iff the two hosts match. Used to release
3238c2ecf20Sopenharmony_ci *	all resources bound to a specific host.
3248c2ecf20Sopenharmony_ci *
3258c2ecf20Sopenharmony_ci * nlmsvc_is_client:
3268c2ecf20Sopenharmony_ci *	returns 1 iff the host is a client.
3278c2ecf20Sopenharmony_ci *	Used by nlmsvc_invalidate_all
3288c2ecf20Sopenharmony_ci */
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_cistatic int
3318c2ecf20Sopenharmony_cinlmsvc_mark_host(void *data, struct nlm_host *hint)
3328c2ecf20Sopenharmony_ci{
3338c2ecf20Sopenharmony_ci	struct nlm_host *host = data;
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	if ((hint->net == NULL) ||
3368c2ecf20Sopenharmony_ci	    (host->net == hint->net))
3378c2ecf20Sopenharmony_ci		host->h_inuse = 1;
3388c2ecf20Sopenharmony_ci	return 0;
3398c2ecf20Sopenharmony_ci}
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_cistatic int
3428c2ecf20Sopenharmony_cinlmsvc_same_host(void *data, struct nlm_host *other)
3438c2ecf20Sopenharmony_ci{
3448c2ecf20Sopenharmony_ci	struct nlm_host *host = data;
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	return host == other;
3478c2ecf20Sopenharmony_ci}
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_cistatic int
3508c2ecf20Sopenharmony_cinlmsvc_is_client(void *data, struct nlm_host *dummy)
3518c2ecf20Sopenharmony_ci{
3528c2ecf20Sopenharmony_ci	struct nlm_host *host = data;
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci	if (host->h_server) {
3558c2ecf20Sopenharmony_ci		/* we are destroying locks even though the client
3568c2ecf20Sopenharmony_ci		 * hasn't asked us too, so don't unmonitor the
3578c2ecf20Sopenharmony_ci		 * client
3588c2ecf20Sopenharmony_ci		 */
3598c2ecf20Sopenharmony_ci		if (host->h_nsmhandle)
3608c2ecf20Sopenharmony_ci			host->h_nsmhandle->sm_sticky = 1;
3618c2ecf20Sopenharmony_ci		return 1;
3628c2ecf20Sopenharmony_ci	} else
3638c2ecf20Sopenharmony_ci		return 0;
3648c2ecf20Sopenharmony_ci}
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci/*
3678c2ecf20Sopenharmony_ci * Mark all hosts that still hold resources
3688c2ecf20Sopenharmony_ci */
3698c2ecf20Sopenharmony_civoid
3708c2ecf20Sopenharmony_cinlmsvc_mark_resources(struct net *net)
3718c2ecf20Sopenharmony_ci{
3728c2ecf20Sopenharmony_ci	struct nlm_host hint;
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci	dprintk("lockd: %s for net %x\n", __func__, net ? net->ns.inum : 0);
3758c2ecf20Sopenharmony_ci	hint.net = net;
3768c2ecf20Sopenharmony_ci	nlm_traverse_files(&hint, nlmsvc_mark_host, NULL);
3778c2ecf20Sopenharmony_ci}
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci/*
3808c2ecf20Sopenharmony_ci * Release all resources held by the given client
3818c2ecf20Sopenharmony_ci */
3828c2ecf20Sopenharmony_civoid
3838c2ecf20Sopenharmony_cinlmsvc_free_host_resources(struct nlm_host *host)
3848c2ecf20Sopenharmony_ci{
3858c2ecf20Sopenharmony_ci	dprintk("lockd: nlmsvc_free_host_resources\n");
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci	if (nlm_traverse_files(host, nlmsvc_same_host, NULL)) {
3888c2ecf20Sopenharmony_ci		printk(KERN_WARNING
3898c2ecf20Sopenharmony_ci			"lockd: couldn't remove all locks held by %s\n",
3908c2ecf20Sopenharmony_ci			host->h_name);
3918c2ecf20Sopenharmony_ci		BUG();
3928c2ecf20Sopenharmony_ci	}
3938c2ecf20Sopenharmony_ci}
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci/**
3968c2ecf20Sopenharmony_ci * nlmsvc_invalidate_all - remove all locks held for clients
3978c2ecf20Sopenharmony_ci *
3988c2ecf20Sopenharmony_ci * Release all locks held by NFS clients.
3998c2ecf20Sopenharmony_ci *
4008c2ecf20Sopenharmony_ci */
4018c2ecf20Sopenharmony_civoid
4028c2ecf20Sopenharmony_cinlmsvc_invalidate_all(void)
4038c2ecf20Sopenharmony_ci{
4048c2ecf20Sopenharmony_ci	/*
4058c2ecf20Sopenharmony_ci	 * Previously, the code would call
4068c2ecf20Sopenharmony_ci	 * nlmsvc_free_host_resources for each client in
4078c2ecf20Sopenharmony_ci	 * turn, which is about as inefficient as it gets.
4088c2ecf20Sopenharmony_ci	 * Now we just do it once in nlm_traverse_files.
4098c2ecf20Sopenharmony_ci	 */
4108c2ecf20Sopenharmony_ci	nlm_traverse_files(NULL, nlmsvc_is_client, NULL);
4118c2ecf20Sopenharmony_ci}
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_cistatic int
4148c2ecf20Sopenharmony_cinlmsvc_match_sb(void *datap, struct nlm_file *file)
4158c2ecf20Sopenharmony_ci{
4168c2ecf20Sopenharmony_ci	struct super_block *sb = datap;
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci	return sb == locks_inode(file->f_file)->i_sb;
4198c2ecf20Sopenharmony_ci}
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci/**
4228c2ecf20Sopenharmony_ci * nlmsvc_unlock_all_by_sb - release locks held on this file system
4238c2ecf20Sopenharmony_ci * @sb: super block
4248c2ecf20Sopenharmony_ci *
4258c2ecf20Sopenharmony_ci * Release all locks held by clients accessing this file system.
4268c2ecf20Sopenharmony_ci */
4278c2ecf20Sopenharmony_ciint
4288c2ecf20Sopenharmony_cinlmsvc_unlock_all_by_sb(struct super_block *sb)
4298c2ecf20Sopenharmony_ci{
4308c2ecf20Sopenharmony_ci	int ret;
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci	ret = nlm_traverse_files(sb, nlmsvc_always_match, nlmsvc_match_sb);
4338c2ecf20Sopenharmony_ci	return ret ? -EIO : 0;
4348c2ecf20Sopenharmony_ci}
4358c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(nlmsvc_unlock_all_by_sb);
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_cistatic int
4388c2ecf20Sopenharmony_cinlmsvc_match_ip(void *datap, struct nlm_host *host)
4398c2ecf20Sopenharmony_ci{
4408c2ecf20Sopenharmony_ci	return rpc_cmp_addr(nlm_srcaddr(host), datap);
4418c2ecf20Sopenharmony_ci}
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci/**
4448c2ecf20Sopenharmony_ci * nlmsvc_unlock_all_by_ip - release local locks by IP address
4458c2ecf20Sopenharmony_ci * @server_addr: server's IP address as seen by clients
4468c2ecf20Sopenharmony_ci *
4478c2ecf20Sopenharmony_ci * Release all locks held by clients accessing this host
4488c2ecf20Sopenharmony_ci * via the passed in IP address.
4498c2ecf20Sopenharmony_ci */
4508c2ecf20Sopenharmony_ciint
4518c2ecf20Sopenharmony_cinlmsvc_unlock_all_by_ip(struct sockaddr *server_addr)
4528c2ecf20Sopenharmony_ci{
4538c2ecf20Sopenharmony_ci	int ret;
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	ret = nlm_traverse_files(server_addr, nlmsvc_match_ip, NULL);
4568c2ecf20Sopenharmony_ci	return ret ? -EIO : 0;
4578c2ecf20Sopenharmony_ci}
4588c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(nlmsvc_unlock_all_by_ip);
459