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