162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * linux/fs/lockd/svcsubs.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Various support routines for the NLM server. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de> 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/types.h> 1162306a36Sopenharmony_ci#include <linux/string.h> 1262306a36Sopenharmony_ci#include <linux/time.h> 1362306a36Sopenharmony_ci#include <linux/in.h> 1462306a36Sopenharmony_ci#include <linux/slab.h> 1562306a36Sopenharmony_ci#include <linux/mutex.h> 1662306a36Sopenharmony_ci#include <linux/sunrpc/svc.h> 1762306a36Sopenharmony_ci#include <linux/sunrpc/addr.h> 1862306a36Sopenharmony_ci#include <linux/lockd/lockd.h> 1962306a36Sopenharmony_ci#include <linux/lockd/share.h> 2062306a36Sopenharmony_ci#include <linux/module.h> 2162306a36Sopenharmony_ci#include <linux/mount.h> 2262306a36Sopenharmony_ci#include <uapi/linux/nfs2.h> 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#define NLMDBG_FACILITY NLMDBG_SVCSUBS 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci/* 2862306a36Sopenharmony_ci * Global file hash table 2962306a36Sopenharmony_ci */ 3062306a36Sopenharmony_ci#define FILE_HASH_BITS 7 3162306a36Sopenharmony_ci#define FILE_NRHASH (1<<FILE_HASH_BITS) 3262306a36Sopenharmony_cistatic struct hlist_head nlm_files[FILE_NRHASH]; 3362306a36Sopenharmony_cistatic DEFINE_MUTEX(nlm_file_mutex); 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci#ifdef CONFIG_SUNRPC_DEBUG 3662306a36Sopenharmony_cistatic inline void nlm_debug_print_fh(char *msg, struct nfs_fh *f) 3762306a36Sopenharmony_ci{ 3862306a36Sopenharmony_ci u32 *fhp = (u32*)f->data; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci /* print the first 32 bytes of the fh */ 4162306a36Sopenharmony_ci dprintk("lockd: %s (%08x %08x %08x %08x %08x %08x %08x %08x)\n", 4262306a36Sopenharmony_ci msg, fhp[0], fhp[1], fhp[2], fhp[3], 4362306a36Sopenharmony_ci fhp[4], fhp[5], fhp[6], fhp[7]); 4462306a36Sopenharmony_ci} 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cistatic inline void nlm_debug_print_file(char *msg, struct nlm_file *file) 4762306a36Sopenharmony_ci{ 4862306a36Sopenharmony_ci struct inode *inode = nlmsvc_file_inode(file); 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci dprintk("lockd: %s %s/%ld\n", 5162306a36Sopenharmony_ci msg, inode->i_sb->s_id, inode->i_ino); 5262306a36Sopenharmony_ci} 5362306a36Sopenharmony_ci#else 5462306a36Sopenharmony_cistatic inline void nlm_debug_print_fh(char *msg, struct nfs_fh *f) 5562306a36Sopenharmony_ci{ 5662306a36Sopenharmony_ci return; 5762306a36Sopenharmony_ci} 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_cistatic inline void nlm_debug_print_file(char *msg, struct nlm_file *file) 6062306a36Sopenharmony_ci{ 6162306a36Sopenharmony_ci return; 6262306a36Sopenharmony_ci} 6362306a36Sopenharmony_ci#endif 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_cistatic inline unsigned int file_hash(struct nfs_fh *f) 6662306a36Sopenharmony_ci{ 6762306a36Sopenharmony_ci unsigned int tmp=0; 6862306a36Sopenharmony_ci int i; 6962306a36Sopenharmony_ci for (i=0; i<NFS2_FHSIZE;i++) 7062306a36Sopenharmony_ci tmp += f->data[i]; 7162306a36Sopenharmony_ci return tmp & (FILE_NRHASH - 1); 7262306a36Sopenharmony_ci} 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ciint lock_to_openmode(struct file_lock *lock) 7562306a36Sopenharmony_ci{ 7662306a36Sopenharmony_ci return (lock->fl_type == F_WRLCK) ? O_WRONLY : O_RDONLY; 7762306a36Sopenharmony_ci} 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci/* 8062306a36Sopenharmony_ci * Open the file. Note that if we're reexporting, for example, 8162306a36Sopenharmony_ci * this could block the lockd thread for a while. 8262306a36Sopenharmony_ci * 8362306a36Sopenharmony_ci * We have to make sure we have the right credential to open 8462306a36Sopenharmony_ci * the file. 8562306a36Sopenharmony_ci */ 8662306a36Sopenharmony_cistatic __be32 nlm_do_fopen(struct svc_rqst *rqstp, 8762306a36Sopenharmony_ci struct nlm_file *file, int mode) 8862306a36Sopenharmony_ci{ 8962306a36Sopenharmony_ci struct file **fp = &file->f_file[mode]; 9062306a36Sopenharmony_ci __be32 nfserr; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci if (*fp) 9362306a36Sopenharmony_ci return 0; 9462306a36Sopenharmony_ci nfserr = nlmsvc_ops->fopen(rqstp, &file->f_handle, fp, mode); 9562306a36Sopenharmony_ci if (nfserr) 9662306a36Sopenharmony_ci dprintk("lockd: open failed (error %d)\n", nfserr); 9762306a36Sopenharmony_ci return nfserr; 9862306a36Sopenharmony_ci} 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci/* 10162306a36Sopenharmony_ci * Lookup file info. If it doesn't exist, create a file info struct 10262306a36Sopenharmony_ci * and open a (VFS) file for the given inode. 10362306a36Sopenharmony_ci */ 10462306a36Sopenharmony_ci__be32 10562306a36Sopenharmony_cinlm_lookup_file(struct svc_rqst *rqstp, struct nlm_file **result, 10662306a36Sopenharmony_ci struct nlm_lock *lock) 10762306a36Sopenharmony_ci{ 10862306a36Sopenharmony_ci struct nlm_file *file; 10962306a36Sopenharmony_ci unsigned int hash; 11062306a36Sopenharmony_ci __be32 nfserr; 11162306a36Sopenharmony_ci int mode; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci nlm_debug_print_fh("nlm_lookup_file", &lock->fh); 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci hash = file_hash(&lock->fh); 11662306a36Sopenharmony_ci mode = lock_to_openmode(&lock->fl); 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci /* Lock file table */ 11962306a36Sopenharmony_ci mutex_lock(&nlm_file_mutex); 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci hlist_for_each_entry(file, &nlm_files[hash], f_list) 12262306a36Sopenharmony_ci if (!nfs_compare_fh(&file->f_handle, &lock->fh)) { 12362306a36Sopenharmony_ci mutex_lock(&file->f_mutex); 12462306a36Sopenharmony_ci nfserr = nlm_do_fopen(rqstp, file, mode); 12562306a36Sopenharmony_ci mutex_unlock(&file->f_mutex); 12662306a36Sopenharmony_ci goto found; 12762306a36Sopenharmony_ci } 12862306a36Sopenharmony_ci nlm_debug_print_fh("creating file for", &lock->fh); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci nfserr = nlm_lck_denied_nolocks; 13162306a36Sopenharmony_ci file = kzalloc(sizeof(*file), GFP_KERNEL); 13262306a36Sopenharmony_ci if (!file) 13362306a36Sopenharmony_ci goto out_free; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci memcpy(&file->f_handle, &lock->fh, sizeof(struct nfs_fh)); 13662306a36Sopenharmony_ci mutex_init(&file->f_mutex); 13762306a36Sopenharmony_ci INIT_HLIST_NODE(&file->f_list); 13862306a36Sopenharmony_ci INIT_LIST_HEAD(&file->f_blocks); 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci nfserr = nlm_do_fopen(rqstp, file, mode); 14162306a36Sopenharmony_ci if (nfserr) 14262306a36Sopenharmony_ci goto out_unlock; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci hlist_add_head(&file->f_list, &nlm_files[hash]); 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_cifound: 14762306a36Sopenharmony_ci dprintk("lockd: found file %p (count %d)\n", file, file->f_count); 14862306a36Sopenharmony_ci *result = file; 14962306a36Sopenharmony_ci file->f_count++; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ciout_unlock: 15262306a36Sopenharmony_ci mutex_unlock(&nlm_file_mutex); 15362306a36Sopenharmony_ci return nfserr; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ciout_free: 15662306a36Sopenharmony_ci kfree(file); 15762306a36Sopenharmony_ci goto out_unlock; 15862306a36Sopenharmony_ci} 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci/* 16162306a36Sopenharmony_ci * Delete a file after having released all locks, blocks and shares 16262306a36Sopenharmony_ci */ 16362306a36Sopenharmony_cistatic inline void 16462306a36Sopenharmony_cinlm_delete_file(struct nlm_file *file) 16562306a36Sopenharmony_ci{ 16662306a36Sopenharmony_ci nlm_debug_print_file("closing file", file); 16762306a36Sopenharmony_ci if (!hlist_unhashed(&file->f_list)) { 16862306a36Sopenharmony_ci hlist_del(&file->f_list); 16962306a36Sopenharmony_ci if (file->f_file[O_RDONLY]) 17062306a36Sopenharmony_ci nlmsvc_ops->fclose(file->f_file[O_RDONLY]); 17162306a36Sopenharmony_ci if (file->f_file[O_WRONLY]) 17262306a36Sopenharmony_ci nlmsvc_ops->fclose(file->f_file[O_WRONLY]); 17362306a36Sopenharmony_ci kfree(file); 17462306a36Sopenharmony_ci } else { 17562306a36Sopenharmony_ci printk(KERN_WARNING "lockd: attempt to release unknown file!\n"); 17662306a36Sopenharmony_ci } 17762306a36Sopenharmony_ci} 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_cistatic int nlm_unlock_files(struct nlm_file *file, const struct file_lock *fl) 18062306a36Sopenharmony_ci{ 18162306a36Sopenharmony_ci struct file_lock lock; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci locks_init_lock(&lock); 18462306a36Sopenharmony_ci lock.fl_type = F_UNLCK; 18562306a36Sopenharmony_ci lock.fl_start = 0; 18662306a36Sopenharmony_ci lock.fl_end = OFFSET_MAX; 18762306a36Sopenharmony_ci lock.fl_owner = fl->fl_owner; 18862306a36Sopenharmony_ci lock.fl_pid = fl->fl_pid; 18962306a36Sopenharmony_ci lock.fl_flags = FL_POSIX; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci lock.fl_file = file->f_file[O_RDONLY]; 19262306a36Sopenharmony_ci if (lock.fl_file && vfs_lock_file(lock.fl_file, F_SETLK, &lock, NULL)) 19362306a36Sopenharmony_ci goto out_err; 19462306a36Sopenharmony_ci lock.fl_file = file->f_file[O_WRONLY]; 19562306a36Sopenharmony_ci if (lock.fl_file && vfs_lock_file(lock.fl_file, F_SETLK, &lock, NULL)) 19662306a36Sopenharmony_ci goto out_err; 19762306a36Sopenharmony_ci return 0; 19862306a36Sopenharmony_ciout_err: 19962306a36Sopenharmony_ci pr_warn("lockd: unlock failure in %s:%d\n", __FILE__, __LINE__); 20062306a36Sopenharmony_ci return 1; 20162306a36Sopenharmony_ci} 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci/* 20462306a36Sopenharmony_ci * Loop over all locks on the given file and perform the specified 20562306a36Sopenharmony_ci * action. 20662306a36Sopenharmony_ci */ 20762306a36Sopenharmony_cistatic int 20862306a36Sopenharmony_cinlm_traverse_locks(struct nlm_host *host, struct nlm_file *file, 20962306a36Sopenharmony_ci nlm_host_match_fn_t match) 21062306a36Sopenharmony_ci{ 21162306a36Sopenharmony_ci struct inode *inode = nlmsvc_file_inode(file); 21262306a36Sopenharmony_ci struct file_lock *fl; 21362306a36Sopenharmony_ci struct file_lock_context *flctx = locks_inode_context(inode); 21462306a36Sopenharmony_ci struct nlm_host *lockhost; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci if (!flctx || list_empty_careful(&flctx->flc_posix)) 21762306a36Sopenharmony_ci return 0; 21862306a36Sopenharmony_ciagain: 21962306a36Sopenharmony_ci file->f_locks = 0; 22062306a36Sopenharmony_ci spin_lock(&flctx->flc_lock); 22162306a36Sopenharmony_ci list_for_each_entry(fl, &flctx->flc_posix, fl_list) { 22262306a36Sopenharmony_ci if (fl->fl_lmops != &nlmsvc_lock_operations) 22362306a36Sopenharmony_ci continue; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci /* update current lock count */ 22662306a36Sopenharmony_ci file->f_locks++; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci lockhost = ((struct nlm_lockowner *)fl->fl_owner)->host; 22962306a36Sopenharmony_ci if (match(lockhost, host)) { 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci spin_unlock(&flctx->flc_lock); 23262306a36Sopenharmony_ci if (nlm_unlock_files(file, fl)) 23362306a36Sopenharmony_ci return 1; 23462306a36Sopenharmony_ci goto again; 23562306a36Sopenharmony_ci } 23662306a36Sopenharmony_ci } 23762306a36Sopenharmony_ci spin_unlock(&flctx->flc_lock); 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci return 0; 24062306a36Sopenharmony_ci} 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_cistatic int 24362306a36Sopenharmony_cinlmsvc_always_match(void *dummy1, struct nlm_host *dummy2) 24462306a36Sopenharmony_ci{ 24562306a36Sopenharmony_ci return 1; 24662306a36Sopenharmony_ci} 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci/* 24962306a36Sopenharmony_ci * Inspect a single file 25062306a36Sopenharmony_ci */ 25162306a36Sopenharmony_cistatic inline int 25262306a36Sopenharmony_cinlm_inspect_file(struct nlm_host *host, struct nlm_file *file, nlm_host_match_fn_t match) 25362306a36Sopenharmony_ci{ 25462306a36Sopenharmony_ci nlmsvc_traverse_blocks(host, file, match); 25562306a36Sopenharmony_ci nlmsvc_traverse_shares(host, file, match); 25662306a36Sopenharmony_ci return nlm_traverse_locks(host, file, match); 25762306a36Sopenharmony_ci} 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci/* 26062306a36Sopenharmony_ci * Quick check whether there are still any locks, blocks or 26162306a36Sopenharmony_ci * shares on a given file. 26262306a36Sopenharmony_ci */ 26362306a36Sopenharmony_cistatic inline int 26462306a36Sopenharmony_cinlm_file_inuse(struct nlm_file *file) 26562306a36Sopenharmony_ci{ 26662306a36Sopenharmony_ci struct inode *inode = nlmsvc_file_inode(file); 26762306a36Sopenharmony_ci struct file_lock *fl; 26862306a36Sopenharmony_ci struct file_lock_context *flctx = locks_inode_context(inode); 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci if (file->f_count || !list_empty(&file->f_blocks) || file->f_shares) 27162306a36Sopenharmony_ci return 1; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci if (flctx && !list_empty_careful(&flctx->flc_posix)) { 27462306a36Sopenharmony_ci spin_lock(&flctx->flc_lock); 27562306a36Sopenharmony_ci list_for_each_entry(fl, &flctx->flc_posix, fl_list) { 27662306a36Sopenharmony_ci if (fl->fl_lmops == &nlmsvc_lock_operations) { 27762306a36Sopenharmony_ci spin_unlock(&flctx->flc_lock); 27862306a36Sopenharmony_ci return 1; 27962306a36Sopenharmony_ci } 28062306a36Sopenharmony_ci } 28162306a36Sopenharmony_ci spin_unlock(&flctx->flc_lock); 28262306a36Sopenharmony_ci } 28362306a36Sopenharmony_ci file->f_locks = 0; 28462306a36Sopenharmony_ci return 0; 28562306a36Sopenharmony_ci} 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_cistatic void nlm_close_files(struct nlm_file *file) 28862306a36Sopenharmony_ci{ 28962306a36Sopenharmony_ci if (file->f_file[O_RDONLY]) 29062306a36Sopenharmony_ci nlmsvc_ops->fclose(file->f_file[O_RDONLY]); 29162306a36Sopenharmony_ci if (file->f_file[O_WRONLY]) 29262306a36Sopenharmony_ci nlmsvc_ops->fclose(file->f_file[O_WRONLY]); 29362306a36Sopenharmony_ci} 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci/* 29662306a36Sopenharmony_ci * Loop over all files in the file table. 29762306a36Sopenharmony_ci */ 29862306a36Sopenharmony_cistatic int 29962306a36Sopenharmony_cinlm_traverse_files(void *data, nlm_host_match_fn_t match, 30062306a36Sopenharmony_ci int (*is_failover_file)(void *data, struct nlm_file *file)) 30162306a36Sopenharmony_ci{ 30262306a36Sopenharmony_ci struct hlist_node *next; 30362306a36Sopenharmony_ci struct nlm_file *file; 30462306a36Sopenharmony_ci int i, ret = 0; 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci mutex_lock(&nlm_file_mutex); 30762306a36Sopenharmony_ci for (i = 0; i < FILE_NRHASH; i++) { 30862306a36Sopenharmony_ci hlist_for_each_entry_safe(file, next, &nlm_files[i], f_list) { 30962306a36Sopenharmony_ci if (is_failover_file && !is_failover_file(data, file)) 31062306a36Sopenharmony_ci continue; 31162306a36Sopenharmony_ci file->f_count++; 31262306a36Sopenharmony_ci mutex_unlock(&nlm_file_mutex); 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci /* Traverse locks, blocks and shares of this file 31562306a36Sopenharmony_ci * and update file->f_locks count */ 31662306a36Sopenharmony_ci if (nlm_inspect_file(data, file, match)) 31762306a36Sopenharmony_ci ret = 1; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci mutex_lock(&nlm_file_mutex); 32062306a36Sopenharmony_ci file->f_count--; 32162306a36Sopenharmony_ci /* No more references to this file. Let go of it. */ 32262306a36Sopenharmony_ci if (list_empty(&file->f_blocks) && !file->f_locks 32362306a36Sopenharmony_ci && !file->f_shares && !file->f_count) { 32462306a36Sopenharmony_ci hlist_del(&file->f_list); 32562306a36Sopenharmony_ci nlm_close_files(file); 32662306a36Sopenharmony_ci kfree(file); 32762306a36Sopenharmony_ci } 32862306a36Sopenharmony_ci } 32962306a36Sopenharmony_ci } 33062306a36Sopenharmony_ci mutex_unlock(&nlm_file_mutex); 33162306a36Sopenharmony_ci return ret; 33262306a36Sopenharmony_ci} 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci/* 33562306a36Sopenharmony_ci * Release file. If there are no more remote locks on this file, 33662306a36Sopenharmony_ci * close it and free the handle. 33762306a36Sopenharmony_ci * 33862306a36Sopenharmony_ci * Note that we can't do proper reference counting without major 33962306a36Sopenharmony_ci * contortions because the code in fs/locks.c creates, deletes and 34062306a36Sopenharmony_ci * splits locks without notification. Our only way is to walk the 34162306a36Sopenharmony_ci * entire lock list each time we remove a lock. 34262306a36Sopenharmony_ci */ 34362306a36Sopenharmony_civoid 34462306a36Sopenharmony_cinlm_release_file(struct nlm_file *file) 34562306a36Sopenharmony_ci{ 34662306a36Sopenharmony_ci dprintk("lockd: nlm_release_file(%p, ct = %d)\n", 34762306a36Sopenharmony_ci file, file->f_count); 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci /* Lock file table */ 35062306a36Sopenharmony_ci mutex_lock(&nlm_file_mutex); 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci /* If there are no more locks etc, delete the file */ 35362306a36Sopenharmony_ci if (--file->f_count == 0 && !nlm_file_inuse(file)) 35462306a36Sopenharmony_ci nlm_delete_file(file); 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci mutex_unlock(&nlm_file_mutex); 35762306a36Sopenharmony_ci} 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci/* 36062306a36Sopenharmony_ci * Helpers function for resource traversal 36162306a36Sopenharmony_ci * 36262306a36Sopenharmony_ci * nlmsvc_mark_host: 36362306a36Sopenharmony_ci * used by the garbage collector; simply sets h_inuse only for those 36462306a36Sopenharmony_ci * hosts, which passed network check. 36562306a36Sopenharmony_ci * Always returns 0. 36662306a36Sopenharmony_ci * 36762306a36Sopenharmony_ci * nlmsvc_same_host: 36862306a36Sopenharmony_ci * returns 1 iff the two hosts match. Used to release 36962306a36Sopenharmony_ci * all resources bound to a specific host. 37062306a36Sopenharmony_ci * 37162306a36Sopenharmony_ci * nlmsvc_is_client: 37262306a36Sopenharmony_ci * returns 1 iff the host is a client. 37362306a36Sopenharmony_ci * Used by nlmsvc_invalidate_all 37462306a36Sopenharmony_ci */ 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_cistatic int 37762306a36Sopenharmony_cinlmsvc_mark_host(void *data, struct nlm_host *hint) 37862306a36Sopenharmony_ci{ 37962306a36Sopenharmony_ci struct nlm_host *host = data; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci if ((hint->net == NULL) || 38262306a36Sopenharmony_ci (host->net == hint->net)) 38362306a36Sopenharmony_ci host->h_inuse = 1; 38462306a36Sopenharmony_ci return 0; 38562306a36Sopenharmony_ci} 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_cistatic int 38862306a36Sopenharmony_cinlmsvc_same_host(void *data, struct nlm_host *other) 38962306a36Sopenharmony_ci{ 39062306a36Sopenharmony_ci struct nlm_host *host = data; 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci return host == other; 39362306a36Sopenharmony_ci} 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_cistatic int 39662306a36Sopenharmony_cinlmsvc_is_client(void *data, struct nlm_host *dummy) 39762306a36Sopenharmony_ci{ 39862306a36Sopenharmony_ci struct nlm_host *host = data; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci if (host->h_server) { 40162306a36Sopenharmony_ci /* we are destroying locks even though the client 40262306a36Sopenharmony_ci * hasn't asked us too, so don't unmonitor the 40362306a36Sopenharmony_ci * client 40462306a36Sopenharmony_ci */ 40562306a36Sopenharmony_ci if (host->h_nsmhandle) 40662306a36Sopenharmony_ci host->h_nsmhandle->sm_sticky = 1; 40762306a36Sopenharmony_ci return 1; 40862306a36Sopenharmony_ci } else 40962306a36Sopenharmony_ci return 0; 41062306a36Sopenharmony_ci} 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci/* 41362306a36Sopenharmony_ci * Mark all hosts that still hold resources 41462306a36Sopenharmony_ci */ 41562306a36Sopenharmony_civoid 41662306a36Sopenharmony_cinlmsvc_mark_resources(struct net *net) 41762306a36Sopenharmony_ci{ 41862306a36Sopenharmony_ci struct nlm_host hint; 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci dprintk("lockd: %s for net %x\n", __func__, net ? net->ns.inum : 0); 42162306a36Sopenharmony_ci hint.net = net; 42262306a36Sopenharmony_ci nlm_traverse_files(&hint, nlmsvc_mark_host, NULL); 42362306a36Sopenharmony_ci} 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci/* 42662306a36Sopenharmony_ci * Release all resources held by the given client 42762306a36Sopenharmony_ci */ 42862306a36Sopenharmony_civoid 42962306a36Sopenharmony_cinlmsvc_free_host_resources(struct nlm_host *host) 43062306a36Sopenharmony_ci{ 43162306a36Sopenharmony_ci dprintk("lockd: nlmsvc_free_host_resources\n"); 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci if (nlm_traverse_files(host, nlmsvc_same_host, NULL)) { 43462306a36Sopenharmony_ci printk(KERN_WARNING 43562306a36Sopenharmony_ci "lockd: couldn't remove all locks held by %s\n", 43662306a36Sopenharmony_ci host->h_name); 43762306a36Sopenharmony_ci BUG(); 43862306a36Sopenharmony_ci } 43962306a36Sopenharmony_ci} 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci/** 44262306a36Sopenharmony_ci * nlmsvc_invalidate_all - remove all locks held for clients 44362306a36Sopenharmony_ci * 44462306a36Sopenharmony_ci * Release all locks held by NFS clients. 44562306a36Sopenharmony_ci * 44662306a36Sopenharmony_ci */ 44762306a36Sopenharmony_civoid 44862306a36Sopenharmony_cinlmsvc_invalidate_all(void) 44962306a36Sopenharmony_ci{ 45062306a36Sopenharmony_ci /* 45162306a36Sopenharmony_ci * Previously, the code would call 45262306a36Sopenharmony_ci * nlmsvc_free_host_resources for each client in 45362306a36Sopenharmony_ci * turn, which is about as inefficient as it gets. 45462306a36Sopenharmony_ci * Now we just do it once in nlm_traverse_files. 45562306a36Sopenharmony_ci */ 45662306a36Sopenharmony_ci nlm_traverse_files(NULL, nlmsvc_is_client, NULL); 45762306a36Sopenharmony_ci} 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_cistatic int 46162306a36Sopenharmony_cinlmsvc_match_sb(void *datap, struct nlm_file *file) 46262306a36Sopenharmony_ci{ 46362306a36Sopenharmony_ci struct super_block *sb = datap; 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci return sb == nlmsvc_file_inode(file)->i_sb; 46662306a36Sopenharmony_ci} 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci/** 46962306a36Sopenharmony_ci * nlmsvc_unlock_all_by_sb - release locks held on this file system 47062306a36Sopenharmony_ci * @sb: super block 47162306a36Sopenharmony_ci * 47262306a36Sopenharmony_ci * Release all locks held by clients accessing this file system. 47362306a36Sopenharmony_ci */ 47462306a36Sopenharmony_ciint 47562306a36Sopenharmony_cinlmsvc_unlock_all_by_sb(struct super_block *sb) 47662306a36Sopenharmony_ci{ 47762306a36Sopenharmony_ci int ret; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci ret = nlm_traverse_files(sb, nlmsvc_always_match, nlmsvc_match_sb); 48062306a36Sopenharmony_ci return ret ? -EIO : 0; 48162306a36Sopenharmony_ci} 48262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(nlmsvc_unlock_all_by_sb); 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_cistatic int 48562306a36Sopenharmony_cinlmsvc_match_ip(void *datap, struct nlm_host *host) 48662306a36Sopenharmony_ci{ 48762306a36Sopenharmony_ci return rpc_cmp_addr(nlm_srcaddr(host), datap); 48862306a36Sopenharmony_ci} 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci/** 49162306a36Sopenharmony_ci * nlmsvc_unlock_all_by_ip - release local locks by IP address 49262306a36Sopenharmony_ci * @server_addr: server's IP address as seen by clients 49362306a36Sopenharmony_ci * 49462306a36Sopenharmony_ci * Release all locks held by clients accessing this host 49562306a36Sopenharmony_ci * via the passed in IP address. 49662306a36Sopenharmony_ci */ 49762306a36Sopenharmony_ciint 49862306a36Sopenharmony_cinlmsvc_unlock_all_by_ip(struct sockaddr *server_addr) 49962306a36Sopenharmony_ci{ 50062306a36Sopenharmony_ci int ret; 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci ret = nlm_traverse_files(server_addr, nlmsvc_match_ip, NULL); 50362306a36Sopenharmony_ci return ret ? -EIO : 0; 50462306a36Sopenharmony_ci} 50562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(nlmsvc_unlock_all_by_ip); 506