xref: /linux/fs/lockd/lockd.h (revision 0fc8f6200d2313278fbf4539bbab74677c685531)
12c562c6eSChuck Lever /* SPDX-License-Identifier: GPL-2.0 */
22c562c6eSChuck Lever /*
32c562c6eSChuck Lever  * Copyright (C) 1996 Olaf Kirch <okir@monad.swb.de>
42c562c6eSChuck Lever  */
52c562c6eSChuck Lever 
62c562c6eSChuck Lever #ifndef _LOCKD_LOCKD_H
72c562c6eSChuck Lever #define _LOCKD_LOCKD_H
82c562c6eSChuck Lever 
92c562c6eSChuck Lever #include <linux/exportfs.h>
102c562c6eSChuck Lever #include <linux/in.h>
112c562c6eSChuck Lever #include <linux/in6.h>
122c562c6eSChuck Lever #include <net/ipv6.h>
132c562c6eSChuck Lever #include <linux/fs.h>
142c562c6eSChuck Lever #include <linux/kref.h>
152c562c6eSChuck Lever #include <linux/refcount.h>
162c562c6eSChuck Lever #include <linux/utsname.h>
175829352eSChuck Lever #include "nlm.h"
182c562c6eSChuck Lever #include <linux/lockd/bind.h>
19615384a2SChuck Lever #include "xdr.h"
20236f3171SChuck Lever #include <linux/sunrpc/debug.h>
212c562c6eSChuck Lever #include <linux/sunrpc/svc.h>
222c562c6eSChuck Lever 
232c562c6eSChuck Lever /*
24236f3171SChuck Lever  * Enable lockd debugging.
25236f3171SChuck Lever  * Requires CONFIG_SUNRPC_DEBUG.
26236f3171SChuck Lever  */
27236f3171SChuck Lever #undef ifdebug
28236f3171SChuck Lever #if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
29236f3171SChuck Lever # define ifdebug(flag)		if (unlikely(nlm_debug & NLMDBG_##flag))
30236f3171SChuck Lever #else
31236f3171SChuck Lever # define ifdebug(flag)		if (0)
32236f3171SChuck Lever #endif
33236f3171SChuck Lever 
34236f3171SChuck Lever #define NLMDBG_SVC		0x0001
35236f3171SChuck Lever #define NLMDBG_CLIENT		0x0002
36236f3171SChuck Lever #define NLMDBG_CLNTLOCK		0x0004
37236f3171SChuck Lever #define NLMDBG_SVCLOCK		0x0008
38236f3171SChuck Lever #define NLMDBG_MONITOR		0x0010
39236f3171SChuck Lever #define NLMDBG_CLNTSUBS		0x0020
40236f3171SChuck Lever #define NLMDBG_SVCSUBS		0x0040
41236f3171SChuck Lever #define NLMDBG_HOSTCACHE	0x0080
42236f3171SChuck Lever #define NLMDBG_XDR		0x0100
43236f3171SChuck Lever #define NLMDBG_ALL		0x7fff
44236f3171SChuck Lever 
45236f3171SChuck Lever /*
462c562c6eSChuck Lever  * Version string
472c562c6eSChuck Lever  */
482c562c6eSChuck Lever #define LOCKD_VERSION		"0.5"
492c562c6eSChuck Lever 
502c562c6eSChuck Lever /*
512c562c6eSChuck Lever  * Default timeout for RPC calls (seconds)
522c562c6eSChuck Lever  */
532c562c6eSChuck Lever #define LOCKD_DFLT_TIMEO	10
542c562c6eSChuck Lever 
55*4f406a2cSChuck Lever /* error codes new to NLMv4 */
56*4f406a2cSChuck Lever #define	nlm4_deadlock		cpu_to_be32(NLM_DEADLCK)
57*4f406a2cSChuck Lever #define	nlm4_rofs		cpu_to_be32(NLM_ROFS)
58*4f406a2cSChuck Lever #define	nlm4_stale_fh		cpu_to_be32(NLM_STALE_FH)
59*4f406a2cSChuck Lever #define	nlm4_fbig		cpu_to_be32(NLM_FBIG)
60*4f406a2cSChuck Lever #define	nlm4_failed		cpu_to_be32(NLM_FAILED)
61*4f406a2cSChuck Lever 
622c562c6eSChuck Lever /*
632c562c6eSChuck Lever  * Internal-use status codes, not to be placed on the wire.
642c562c6eSChuck Lever  * Version handlers translate these to appropriate wire values.
652c562c6eSChuck Lever  */
662c562c6eSChuck Lever #define nlm__int__drop_reply	cpu_to_be32(30000)
672c562c6eSChuck Lever #define nlm__int__deadlock	cpu_to_be32(30001)
682c562c6eSChuck Lever #define nlm__int__stale_fh	cpu_to_be32(30002)
692c562c6eSChuck Lever #define nlm__int__failed	cpu_to_be32(30003)
702c562c6eSChuck Lever 
712c562c6eSChuck Lever /*
722c562c6eSChuck Lever  * Lockd host handle (used both by the client and server personality).
732c562c6eSChuck Lever  */
742c562c6eSChuck Lever struct nlm_host {
752c562c6eSChuck Lever 	struct hlist_node	h_hash;		/* doubly linked list */
762c562c6eSChuck Lever 	struct sockaddr_storage	h_addr;		/* peer address */
772c562c6eSChuck Lever 	size_t			h_addrlen;
782c562c6eSChuck Lever 	struct sockaddr_storage	h_srcaddr;	/* our address (optional) */
792c562c6eSChuck Lever 	size_t			h_srcaddrlen;
802c562c6eSChuck Lever 	struct rpc_clnt		*h_rpcclnt;	/* RPC client to talk to peer */
812c562c6eSChuck Lever 	char			*h_name;		/* remote hostname */
822c562c6eSChuck Lever 	u32			h_version;	/* interface version */
832c562c6eSChuck Lever 	unsigned short		h_proto;	/* transport proto */
842c562c6eSChuck Lever 	unsigned short		h_reclaiming : 1,
852c562c6eSChuck Lever 				h_server     : 1, /* server side, not client side */
862c562c6eSChuck Lever 				h_noresvport : 1,
872c562c6eSChuck Lever 				h_inuse      : 1;
882c562c6eSChuck Lever 	wait_queue_head_t	h_gracewait;	/* wait while reclaiming */
892c562c6eSChuck Lever 	struct rw_semaphore	h_rwsem;	/* Reboot recovery lock */
902c562c6eSChuck Lever 	u32			h_state;	/* pseudo-state counter */
912c562c6eSChuck Lever 	u32			h_nsmstate;	/* true remote NSM state */
922c562c6eSChuck Lever 	u32			h_pidcount;	/* Pseudopids */
932c562c6eSChuck Lever 	refcount_t		h_count;	/* reference count */
942c562c6eSChuck Lever 	struct mutex		h_mutex;	/* mutex for pmap binding */
952c562c6eSChuck Lever 	unsigned long		h_nextrebind;	/* next portmap call */
962c562c6eSChuck Lever 	unsigned long		h_expires;	/* eligible for GC */
972c562c6eSChuck Lever 	struct list_head	h_lockowners;	/* Lockowners for the client */
982c562c6eSChuck Lever 	spinlock_t		h_lock;
992c562c6eSChuck Lever 	struct list_head	h_granted;	/* Locks in GRANTED state */
1002c562c6eSChuck Lever 	struct list_head	h_reclaim;	/* Locks in RECLAIM state */
1012c562c6eSChuck Lever 	struct nsm_handle	*h_nsmhandle;	/* NSM status handle */
1022c562c6eSChuck Lever 	char			*h_addrbuf;	/* address eyecatcher */
1032c562c6eSChuck Lever 	struct net		*net;		/* host net */
1042c562c6eSChuck Lever 	const struct cred	*h_cred;
1052c562c6eSChuck Lever 	char			nodename[UNX_MAXNODENAME + 1];
1062c562c6eSChuck Lever 	const struct nlmclnt_operations	*h_nlmclnt_ops;	/* Callback ops for NLM users */
1072c562c6eSChuck Lever };
1082c562c6eSChuck Lever 
1092c562c6eSChuck Lever /*
1102c562c6eSChuck Lever  * The largest string sm_addrbuf should hold is a full-size IPv6 address
1112c562c6eSChuck Lever  * (no "::" anywhere) with a scope ID.  The buffer size is computed to
1122c562c6eSChuck Lever  * hold eight groups of colon-separated four-hex-digit numbers, a
1132c562c6eSChuck Lever  * percent sign, a scope id (at most 32 bits, in decimal), and NUL.
1142c562c6eSChuck Lever  */
1152c562c6eSChuck Lever #define NSM_ADDRBUF		((8 * 4 + 7) + (1 + 10) + 1)
1162c562c6eSChuck Lever 
1172c562c6eSChuck Lever struct nsm_handle {
1182c562c6eSChuck Lever 	struct list_head	sm_link;
1192c562c6eSChuck Lever 	refcount_t		sm_count;
1202c562c6eSChuck Lever 	char			*sm_mon_name;
1212c562c6eSChuck Lever 	char			*sm_name;
1222c562c6eSChuck Lever 	struct sockaddr_storage	sm_addr;
1232c562c6eSChuck Lever 	size_t			sm_addrlen;
1242c562c6eSChuck Lever 	unsigned int		sm_monitored : 1,
1252c562c6eSChuck Lever 				sm_sticky : 1;	/* don't unmonitor */
1262c562c6eSChuck Lever 	struct nsm_private	sm_priv;
1272c562c6eSChuck Lever 	char			sm_addrbuf[NSM_ADDRBUF];
1282c562c6eSChuck Lever };
1292c562c6eSChuck Lever 
1302c562c6eSChuck Lever /*
1312c562c6eSChuck Lever  * Rigorous type checking on sockaddr type conversions
1322c562c6eSChuck Lever  */
1332c562c6eSChuck Lever static inline struct sockaddr *nlm_addr(const struct nlm_host *host)
1342c562c6eSChuck Lever {
1352c562c6eSChuck Lever 	return (struct sockaddr *)&host->h_addr;
1362c562c6eSChuck Lever }
1372c562c6eSChuck Lever 
1382c562c6eSChuck Lever static inline struct sockaddr *nlm_srcaddr(const struct nlm_host *host)
1392c562c6eSChuck Lever {
1402c562c6eSChuck Lever 	return (struct sockaddr *)&host->h_srcaddr;
1412c562c6eSChuck Lever }
1422c562c6eSChuck Lever 
1432c562c6eSChuck Lever /*
1442c562c6eSChuck Lever  * Map an fl_owner_t into a unique 32-bit "pid"
1452c562c6eSChuck Lever  */
1462c562c6eSChuck Lever struct nlm_lockowner {
1472c562c6eSChuck Lever 	struct list_head list;
1482c562c6eSChuck Lever 	refcount_t count;
1492c562c6eSChuck Lever 
1502c562c6eSChuck Lever 	struct nlm_host *host;
1512c562c6eSChuck Lever 	fl_owner_t owner;
1522c562c6eSChuck Lever 	uint32_t pid;
1532c562c6eSChuck Lever };
1542c562c6eSChuck Lever 
1552c562c6eSChuck Lever /*
1562c562c6eSChuck Lever  * This is the representation of a blocked client lock.
1572c562c6eSChuck Lever  */
1582c562c6eSChuck Lever struct nlm_wait {
1592c562c6eSChuck Lever 	struct list_head	b_list;		/* linked list */
1602c562c6eSChuck Lever 	wait_queue_head_t	b_wait;		/* where to wait on */
1612c562c6eSChuck Lever 	struct nlm_host		*b_host;
1622c562c6eSChuck Lever 	struct file_lock	*b_lock;	/* local file lock */
1632c562c6eSChuck Lever 	__be32			b_status;	/* grant callback status */
1642c562c6eSChuck Lever };
1652c562c6eSChuck Lever 
1662c562c6eSChuck Lever /*
1672c562c6eSChuck Lever  * Memory chunk for NLM client RPC request.
1682c562c6eSChuck Lever  */
1692c562c6eSChuck Lever #define NLMCLNT_OHSIZE		((__NEW_UTS_LEN) + 10u)
1702c562c6eSChuck Lever struct nlm_rqst {
1712c562c6eSChuck Lever 	refcount_t		a_count;
1722c562c6eSChuck Lever 	unsigned int		a_flags;	/* initial RPC task flags */
1732c562c6eSChuck Lever 	struct nlm_host *	a_host;		/* host handle */
1742c562c6eSChuck Lever 	struct nlm_args		a_args;		/* arguments */
1752c562c6eSChuck Lever 	struct nlm_res		a_res;		/* result */
1762c562c6eSChuck Lever 	struct nlm_block *	a_block;
1772c562c6eSChuck Lever 	unsigned int		a_retries;	/* Retry count */
1782c562c6eSChuck Lever 	u8			a_owner[NLMCLNT_OHSIZE];
1792c562c6eSChuck Lever 	void *	a_callback_data; /* sent to nlmclnt_operations callbacks */
1802c562c6eSChuck Lever };
1812c562c6eSChuck Lever 
1822c562c6eSChuck Lever struct nlm_share;
1832c562c6eSChuck Lever 
1842c562c6eSChuck Lever /*
1852c562c6eSChuck Lever  * This struct describes a file held open by lockd on behalf of
1862c562c6eSChuck Lever  * an NFS client.
1872c562c6eSChuck Lever  */
1882c562c6eSChuck Lever struct nlm_file {
1892c562c6eSChuck Lever 	struct hlist_node	f_list;		/* linked list */
1902c562c6eSChuck Lever 	struct nfs_fh		f_handle;	/* NFS file handle */
1912c562c6eSChuck Lever 	struct file *		f_file[2];	/* VFS file pointers,
1922c562c6eSChuck Lever 						   indexed by O_ flags */
1932c562c6eSChuck Lever 	struct nlm_share *	f_shares;	/* DOS shares */
1942c562c6eSChuck Lever 	struct list_head	f_blocks;	/* blocked locks */
1952c562c6eSChuck Lever 	unsigned int		f_locks;	/* guesstimate # of locks */
1962c562c6eSChuck Lever 	unsigned int		f_count;	/* reference count */
1972c562c6eSChuck Lever 	struct mutex		f_mutex;	/* avoid concurrent access */
1982c562c6eSChuck Lever };
1992c562c6eSChuck Lever 
2002c562c6eSChuck Lever /*
2012c562c6eSChuck Lever  * This is a server block (i.e. a lock requested by some client which
2022c562c6eSChuck Lever  * couldn't be granted because of a conflicting lock).
2032c562c6eSChuck Lever  */
2042c562c6eSChuck Lever #define NLM_NEVER		(~(unsigned long) 0)
2052c562c6eSChuck Lever /* timeout on non-blocking call: */
2062c562c6eSChuck Lever #define NLM_TIMEOUT		(7 * HZ)
2072c562c6eSChuck Lever 
2082c562c6eSChuck Lever struct nlm_block {
2092c562c6eSChuck Lever 	struct kref		b_count;	/* Reference count */
2102c562c6eSChuck Lever 	struct list_head	b_list;		/* linked list of all blocks */
2112c562c6eSChuck Lever 	struct list_head	b_flist;	/* linked list (per file) */
2122c562c6eSChuck Lever 	struct nlm_rqst	*	b_call;		/* RPC args & callback info */
2132c562c6eSChuck Lever 	struct svc_serv *	b_daemon;	/* NLM service */
2142c562c6eSChuck Lever 	struct nlm_host *	b_host;		/* host handle for RPC clnt */
2152c562c6eSChuck Lever 	unsigned long		b_when;		/* next re-xmit */
2162c562c6eSChuck Lever 	unsigned int		b_id;		/* block id */
2172c562c6eSChuck Lever 	unsigned char		b_granted;	/* VFS granted lock */
2182c562c6eSChuck Lever 	struct nlm_file *	b_file;		/* file in question */
2192c562c6eSChuck Lever 	struct cache_req *	b_cache_req;	/* deferred request handling */
2202c562c6eSChuck Lever 	struct cache_deferred_req * b_deferred_req;
2212c562c6eSChuck Lever 	unsigned int		b_flags;	/* block flags */
2222c562c6eSChuck Lever #define B_QUEUED		1	/* lock queued */
2232c562c6eSChuck Lever #define B_GOT_CALLBACK		2	/* got lock or conflicting lock */
2242c562c6eSChuck Lever #define B_TIMED_OUT		4	/* filesystem too slow to respond */
2252c562c6eSChuck Lever };
2262c562c6eSChuck Lever 
2272c562c6eSChuck Lever /*
2282c562c6eSChuck Lever  * Global variables
2292c562c6eSChuck Lever  */
2302c562c6eSChuck Lever extern const struct rpc_program	nlm_program;
23145cd458bSChuck Lever extern const struct svc_version nlmsvc_version1;
23245cd458bSChuck Lever extern const struct svc_version nlmsvc_version3;
2332c562c6eSChuck Lever #ifdef CONFIG_LOCKD_V4
23445cd458bSChuck Lever extern const struct svc_version nlmsvc_version4;
2352c562c6eSChuck Lever #endif
2362c562c6eSChuck Lever extern int			nlmsvc_grace_period;
2372c562c6eSChuck Lever extern unsigned long		nlm_timeout;
2382c562c6eSChuck Lever extern bool			nsm_use_hostnames;
2392c562c6eSChuck Lever extern u32			nsm_local_state;
2402c562c6eSChuck Lever 
2412c562c6eSChuck Lever extern struct timer_list	nlmsvc_retry;
2422c562c6eSChuck Lever 
2432c562c6eSChuck Lever /*
2442c562c6eSChuck Lever  * Lockd client functions
2452c562c6eSChuck Lever  */
2462c562c6eSChuck Lever struct nlm_rqst * nlm_alloc_call(struct nlm_host *host);
2472c562c6eSChuck Lever int		  nlm_async_call(struct nlm_rqst *, u32, const struct rpc_call_ops *);
2482c562c6eSChuck Lever int		  nlm_async_reply(struct nlm_rqst *, u32, const struct rpc_call_ops *);
2492c562c6eSChuck Lever void		  nlmclnt_release_call(struct nlm_rqst *);
2502c562c6eSChuck Lever void		  nlmclnt_prepare_block(struct nlm_wait *block, struct nlm_host *host,
2512c562c6eSChuck Lever 					struct file_lock *fl);
2522c562c6eSChuck Lever void		  nlmclnt_queue_block(struct nlm_wait *block);
2532c562c6eSChuck Lever __be32		  nlmclnt_dequeue_block(struct nlm_wait *block);
2542c562c6eSChuck Lever int		  nlmclnt_wait(struct nlm_wait *block, struct nlm_rqst *req, long timeout);
2552c562c6eSChuck Lever __be32		  nlmclnt_grant(const struct sockaddr *addr,
2562c562c6eSChuck Lever 				const struct nlm_lock *lock);
2572c562c6eSChuck Lever void		  nlmclnt_recovery(struct nlm_host *);
2582c562c6eSChuck Lever int		  nlmclnt_reclaim(struct nlm_host *, struct file_lock *,
2592c562c6eSChuck Lever 				  struct nlm_rqst *);
2602c562c6eSChuck Lever void		  nlmclnt_next_cookie(struct nlm_cookie *);
2612c562c6eSChuck Lever 
2622c562c6eSChuck Lever #ifdef CONFIG_LOCKD_V4
2632c562c6eSChuck Lever extern const struct rpc_version nlm_version4;
2642c562c6eSChuck Lever #endif
2652c562c6eSChuck Lever 
2662c562c6eSChuck Lever /*
2672c562c6eSChuck Lever  * Host cache
2682c562c6eSChuck Lever  */
2692c562c6eSChuck Lever struct nlm_host  *nlmclnt_lookup_host(const struct sockaddr *sap,
2702c562c6eSChuck Lever 					const size_t salen,
2712c562c6eSChuck Lever 					const unsigned short protocol,
2722c562c6eSChuck Lever 					const u32 version,
2732c562c6eSChuck Lever 					const char *hostname,
2742c562c6eSChuck Lever 					int noresvport,
2752c562c6eSChuck Lever 					struct net *net,
2762c562c6eSChuck Lever 					const struct cred *cred);
2772c562c6eSChuck Lever void		  nlmclnt_release_host(struct nlm_host *);
2782c562c6eSChuck Lever struct nlm_host  *nlmsvc_lookup_host(const struct svc_rqst *rqstp,
2792c562c6eSChuck Lever 					const char *hostname,
2802c562c6eSChuck Lever 					const size_t hostname_len);
2812c562c6eSChuck Lever void		  nlmsvc_release_host(struct nlm_host *);
2822c562c6eSChuck Lever struct rpc_clnt * nlm_bind_host(struct nlm_host *);
2832c562c6eSChuck Lever void		  nlm_rebind_host(struct nlm_host *);
2842c562c6eSChuck Lever struct nlm_host * nlm_get_host(struct nlm_host *);
2852c562c6eSChuck Lever void		  nlm_shutdown_hosts(void);
2862c562c6eSChuck Lever void		  nlm_shutdown_hosts_net(struct net *net);
2872c562c6eSChuck Lever void		  nlm_host_rebooted(const struct net *net,
2882c562c6eSChuck Lever 					const struct nlm_reboot *);
2892c562c6eSChuck Lever 
2902c562c6eSChuck Lever /*
2912c562c6eSChuck Lever  * Host monitoring
2922c562c6eSChuck Lever  */
2932c562c6eSChuck Lever int		  nsm_monitor(const struct nlm_host *host);
2942c562c6eSChuck Lever void		  nsm_unmonitor(const struct nlm_host *host);
2952c562c6eSChuck Lever 
2962c562c6eSChuck Lever struct nsm_handle *nsm_get_handle(const struct net *net,
2972c562c6eSChuck Lever 					const struct sockaddr *sap,
2982c562c6eSChuck Lever 					const size_t salen,
2992c562c6eSChuck Lever 					const char *hostname,
3002c562c6eSChuck Lever 					const size_t hostname_len);
3012c562c6eSChuck Lever struct nsm_handle *nsm_reboot_lookup(const struct net *net,
3022c562c6eSChuck Lever 					const struct nlm_reboot *info);
3032c562c6eSChuck Lever void		  nsm_release(struct nsm_handle *nsm);
3042c562c6eSChuck Lever 
3052c562c6eSChuck Lever /*
3062c562c6eSChuck Lever  * This is used in garbage collection and resource reclaim
3072c562c6eSChuck Lever  * A return value != 0 means destroy the lock/block/share
3082c562c6eSChuck Lever  */
3092c562c6eSChuck Lever typedef int	  (*nlm_host_match_fn_t)(void *cur, struct nlm_host *ref);
3102c562c6eSChuck Lever 
3112c562c6eSChuck Lever /*
3122c562c6eSChuck Lever  * Server-side lock handling
3132c562c6eSChuck Lever  */
3142c562c6eSChuck Lever int		  lock_to_openmode(struct file_lock *);
3152c562c6eSChuck Lever __be32		  nlmsvc_lock(struct svc_rqst *, struct nlm_file *,
3162c562c6eSChuck Lever 			      struct nlm_host *, struct nlm_lock *, int,
3172c562c6eSChuck Lever 			      struct nlm_cookie *, int);
3182c562c6eSChuck Lever __be32		  nlmsvc_unlock(struct net *net, struct nlm_file *, struct nlm_lock *);
3192c562c6eSChuck Lever __be32		  nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file,
3202c562c6eSChuck Lever 			struct nlm_host *host, struct nlm_lock *lock,
3212c562c6eSChuck Lever 			struct nlm_lock *conflock);
3222c562c6eSChuck Lever __be32		  nlmsvc_cancel_blocked(struct net *net, struct nlm_file *, struct nlm_lock *);
3232c562c6eSChuck Lever void		  nlmsvc_retry_blocked(struct svc_rqst *rqstp);
3242c562c6eSChuck Lever void		  nlmsvc_traverse_blocks(struct nlm_host *, struct nlm_file *,
3252c562c6eSChuck Lever 					nlm_host_match_fn_t match);
3262c562c6eSChuck Lever void		  nlmsvc_grant_reply(struct nlm_cookie *, __be32);
3272c562c6eSChuck Lever void		  nlmsvc_release_call(struct nlm_rqst *);
3282c562c6eSChuck Lever void		  nlmsvc_locks_init_private(struct file_lock *, struct nlm_host *, pid_t);
32945cd458bSChuck Lever int		  nlmsvc_dispatch(struct svc_rqst *rqstp);
3302c562c6eSChuck Lever 
3312c562c6eSChuck Lever /*
3322c562c6eSChuck Lever  * File handling for the server personality
3332c562c6eSChuck Lever  */
3342c562c6eSChuck Lever __be32		  nlm_lookup_file(struct svc_rqst *, struct nlm_file **,
3352c562c6eSChuck Lever 					struct nlm_lock *);
3362c562c6eSChuck Lever void		  nlm_release_file(struct nlm_file *);
3372c562c6eSChuck Lever void		  nlmsvc_put_lockowner(struct nlm_lockowner *);
3382c562c6eSChuck Lever void		  nlmsvc_release_lockowner(struct nlm_lock *);
3392c562c6eSChuck Lever void		  nlmsvc_mark_resources(struct net *);
3402c562c6eSChuck Lever void		  nlmsvc_free_host_resources(struct nlm_host *);
3412c562c6eSChuck Lever void		  nlmsvc_invalidate_all(void);
3422c562c6eSChuck Lever 
3432c562c6eSChuck Lever static inline struct file *nlmsvc_file_file(const struct nlm_file *file)
3442c562c6eSChuck Lever {
3452c562c6eSChuck Lever 	return file->f_file[O_RDONLY] ?
3462c562c6eSChuck Lever 	       file->f_file[O_RDONLY] : file->f_file[O_WRONLY];
3472c562c6eSChuck Lever }
3482c562c6eSChuck Lever 
3492c562c6eSChuck Lever static inline struct inode *nlmsvc_file_inode(struct nlm_file *file)
3502c562c6eSChuck Lever {
3512c562c6eSChuck Lever 	return file_inode(nlmsvc_file_file(file));
3522c562c6eSChuck Lever }
3532c562c6eSChuck Lever 
3542c562c6eSChuck Lever static inline bool
3552c562c6eSChuck Lever nlmsvc_file_cannot_lock(const struct nlm_file *file)
3562c562c6eSChuck Lever {
3572c562c6eSChuck Lever 	return exportfs_cannot_lock(nlmsvc_file_file(file)->f_path.dentry->d_sb->s_export_op);
3582c562c6eSChuck Lever }
3592c562c6eSChuck Lever 
3602c562c6eSChuck Lever static inline int __nlm_privileged_request4(const struct sockaddr *sap)
3612c562c6eSChuck Lever {
3622c562c6eSChuck Lever 	const struct sockaddr_in *sin = (struct sockaddr_in *)sap;
3632c562c6eSChuck Lever 
3642c562c6eSChuck Lever 	if (ntohs(sin->sin_port) > 1023)
3652c562c6eSChuck Lever 		return 0;
3662c562c6eSChuck Lever 
3672c562c6eSChuck Lever 	return ipv4_is_loopback(sin->sin_addr.s_addr);
3682c562c6eSChuck Lever }
3692c562c6eSChuck Lever 
3702c562c6eSChuck Lever #if IS_ENABLED(CONFIG_IPV6)
3712c562c6eSChuck Lever static inline int __nlm_privileged_request6(const struct sockaddr *sap)
3722c562c6eSChuck Lever {
3732c562c6eSChuck Lever 	const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap;
3742c562c6eSChuck Lever 
3752c562c6eSChuck Lever 	if (ntohs(sin6->sin6_port) > 1023)
3762c562c6eSChuck Lever 		return 0;
3772c562c6eSChuck Lever 
3782c562c6eSChuck Lever 	if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_MAPPED)
3792c562c6eSChuck Lever 		return ipv4_is_loopback(sin6->sin6_addr.s6_addr32[3]);
3802c562c6eSChuck Lever 
3812c562c6eSChuck Lever 	return ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LOOPBACK;
3822c562c6eSChuck Lever }
3832c562c6eSChuck Lever #else	/* IS_ENABLED(CONFIG_IPV6) */
3842c562c6eSChuck Lever static inline int __nlm_privileged_request6(const struct sockaddr *sap)
3852c562c6eSChuck Lever {
3862c562c6eSChuck Lever 	return 0;
3872c562c6eSChuck Lever }
3882c562c6eSChuck Lever #endif	/* IS_ENABLED(CONFIG_IPV6) */
3892c562c6eSChuck Lever 
3902c562c6eSChuck Lever /*
3912c562c6eSChuck Lever  * Ensure incoming requests are from local privileged callers.
3922c562c6eSChuck Lever  *
3932c562c6eSChuck Lever  * Return TRUE if sender is local and is connecting via a privileged port;
3942c562c6eSChuck Lever  * otherwise return FALSE.
3952c562c6eSChuck Lever  */
3962c562c6eSChuck Lever static inline int nlm_privileged_requester(const struct svc_rqst *rqstp)
3972c562c6eSChuck Lever {
3982c562c6eSChuck Lever 	const struct sockaddr *sap = svc_addr(rqstp);
3992c562c6eSChuck Lever 
4002c562c6eSChuck Lever 	switch (sap->sa_family) {
4012c562c6eSChuck Lever 	case AF_INET:
4022c562c6eSChuck Lever 		return __nlm_privileged_request4(sap);
4032c562c6eSChuck Lever 	case AF_INET6:
4042c562c6eSChuck Lever 		return __nlm_privileged_request6(sap);
4052c562c6eSChuck Lever 	default:
4062c562c6eSChuck Lever 		return 0;
4072c562c6eSChuck Lever 	}
4082c562c6eSChuck Lever }
4092c562c6eSChuck Lever 
4102c562c6eSChuck Lever /*
4112c562c6eSChuck Lever  * Compare two NLM locks.
4122c562c6eSChuck Lever  * When the second lock is of type F_UNLCK, this acts like a wildcard.
4132c562c6eSChuck Lever  */
4142c562c6eSChuck Lever static inline int nlm_compare_locks(const struct file_lock *fl1,
4152c562c6eSChuck Lever 				    const struct file_lock *fl2)
4162c562c6eSChuck Lever {
4172c562c6eSChuck Lever 	return file_inode(fl1->c.flc_file) == file_inode(fl2->c.flc_file)
4182c562c6eSChuck Lever 	     && fl1->c.flc_pid   == fl2->c.flc_pid
4192c562c6eSChuck Lever 	     && fl1->c.flc_owner == fl2->c.flc_owner
4202c562c6eSChuck Lever 	     && fl1->fl_start == fl2->fl_start
4212c562c6eSChuck Lever 	     && fl1->fl_end   == fl2->fl_end
4222c562c6eSChuck Lever 	     &&(fl1->c.flc_type  == fl2->c.flc_type || fl2->c.flc_type == F_UNLCK);
4232c562c6eSChuck Lever }
4242c562c6eSChuck Lever 
425b3f76a9bSChuck Lever /**
426b3f76a9bSChuck Lever  * lockd_set_file_lock_range4 - set the byte range of a file_lock
427b3f76a9bSChuck Lever  * @fl: file_lock whose length fields are to be initialized
428b3f76a9bSChuck Lever  * @off: starting offset of the lock, in bytes
429b3f76a9bSChuck Lever  * @len: length of the byte range, in bytes, or zero
430b3f76a9bSChuck Lever  *
431b3f76a9bSChuck Lever  * The NLMv4 protocol represents lock byte ranges as (start, length),
432b3f76a9bSChuck Lever  * where length zero means "lock to end of file." The kernel's file_lock
433b3f76a9bSChuck Lever  * structure uses (start, end) representation. Convert from NLMv4 format
434b3f76a9bSChuck Lever  * to file_lock format, clamping the starting offset and treating
435b3f76a9bSChuck Lever  * arithmetic overflow as "lock to EOF."
436b3f76a9bSChuck Lever  */
437b3f76a9bSChuck Lever static inline void
438b3f76a9bSChuck Lever lockd_set_file_lock_range4(struct file_lock *fl, u64 off, u64 len)
439b3f76a9bSChuck Lever {
440b3f76a9bSChuck Lever 	u64 clamped_off = (off > OFFSET_MAX) ? OFFSET_MAX : off;
441b3f76a9bSChuck Lever 	s64 end = clamped_off + len - 1;
442b3f76a9bSChuck Lever 
443b3f76a9bSChuck Lever 	fl->fl_start = clamped_off;
444b3f76a9bSChuck Lever 	if (len == 0 || end < 0)
445b3f76a9bSChuck Lever 		fl->fl_end = OFFSET_MAX;
446b3f76a9bSChuck Lever 	else
447b3f76a9bSChuck Lever 		fl->fl_end = end;
448b3f76a9bSChuck Lever }
449b3f76a9bSChuck Lever 
4502c562c6eSChuck Lever extern const struct lock_manager_operations nlmsvc_lock_operations;
4512c562c6eSChuck Lever 
4522c562c6eSChuck Lever #endif /* _LOCKD_LOCKD_H */
453