11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * linux/fs/lockd/clntlock.c 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Lock handling for the client side NLM implementation 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de> 71da177e4SLinus Torvalds */ 81da177e4SLinus Torvalds 91da177e4SLinus Torvalds #include <linux/module.h> 101da177e4SLinus Torvalds #include <linux/types.h> 111da177e4SLinus Torvalds #include <linux/time.h> 121da177e4SLinus Torvalds #include <linux/nfs_fs.h> 131da177e4SLinus Torvalds #include <linux/sunrpc/clnt.h> 141da177e4SLinus Torvalds #include <linux/sunrpc/svc.h> 151da177e4SLinus Torvalds #include <linux/lockd/lockd.h> 161da177e4SLinus Torvalds #include <linux/smp_lock.h> 171da177e4SLinus Torvalds 181da177e4SLinus Torvalds #define NLMDBG_FACILITY NLMDBG_CLIENT 191da177e4SLinus Torvalds 201da177e4SLinus Torvalds /* 211da177e4SLinus Torvalds * Local function prototypes 221da177e4SLinus Torvalds */ 231da177e4SLinus Torvalds static int reclaimer(void *ptr); 241da177e4SLinus Torvalds 251da177e4SLinus Torvalds /* 261da177e4SLinus Torvalds * The following functions handle blocking and granting from the 271da177e4SLinus Torvalds * client perspective. 281da177e4SLinus Torvalds */ 291da177e4SLinus Torvalds 301da177e4SLinus Torvalds /* 311da177e4SLinus Torvalds * This is the representation of a blocked client lock. 321da177e4SLinus Torvalds */ 331da177e4SLinus Torvalds struct nlm_wait { 344f15e2b1STrond Myklebust struct list_head b_list; /* linked list */ 351da177e4SLinus Torvalds wait_queue_head_t b_wait; /* where to wait on */ 361da177e4SLinus Torvalds struct nlm_host * b_host; 371da177e4SLinus Torvalds struct file_lock * b_lock; /* local file lock */ 381da177e4SLinus Torvalds unsigned short b_reclaim; /* got to reclaim lock */ 39e8c5c045SAl Viro __be32 b_status; /* grant callback status */ 401da177e4SLinus Torvalds }; 411da177e4SLinus Torvalds 424f15e2b1STrond Myklebust static LIST_HEAD(nlm_blocked); 431da177e4SLinus Torvalds 441da177e4SLinus Torvalds /* 45ecdbf769STrond Myklebust * Queue up a lock for blocking so that the GRANTED request can see it 46ecdbf769STrond Myklebust */ 473a649b88STrond Myklebust struct nlm_wait *nlmclnt_prepare_block(struct nlm_host *host, struct file_lock *fl) 48ecdbf769STrond Myklebust { 49ecdbf769STrond Myklebust struct nlm_wait *block; 50ecdbf769STrond Myklebust 51ecdbf769STrond Myklebust block = kmalloc(sizeof(*block), GFP_KERNEL); 523a649b88STrond Myklebust if (block != NULL) { 53ecdbf769STrond Myklebust block->b_host = host; 54ecdbf769STrond Myklebust block->b_lock = fl; 55ecdbf769STrond Myklebust init_waitqueue_head(&block->b_wait); 56e8c5c045SAl Viro block->b_status = nlm_lck_blocked; 57ecdbf769STrond Myklebust list_add(&block->b_list, &nlm_blocked); 583a649b88STrond Myklebust } 593a649b88STrond Myklebust return block; 60ecdbf769STrond Myklebust } 61ecdbf769STrond Myklebust 623a649b88STrond Myklebust void nlmclnt_finish_block(struct nlm_wait *block) 63ecdbf769STrond Myklebust { 64ecdbf769STrond Myklebust if (block == NULL) 65ecdbf769STrond Myklebust return; 66ecdbf769STrond Myklebust list_del(&block->b_list); 67ecdbf769STrond Myklebust kfree(block); 68ecdbf769STrond Myklebust } 69ecdbf769STrond Myklebust 70ecdbf769STrond Myklebust /* 711da177e4SLinus Torvalds * Block on a lock 721da177e4SLinus Torvalds */ 733a649b88STrond Myklebust int nlmclnt_block(struct nlm_wait *block, struct nlm_rqst *req, long timeout) 741da177e4SLinus Torvalds { 75ecdbf769STrond Myklebust long ret; 761da177e4SLinus Torvalds 77ecdbf769STrond Myklebust /* A borken server might ask us to block even if we didn't 78ecdbf769STrond Myklebust * request it. Just say no! 79ecdbf769STrond Myklebust */ 803a649b88STrond Myklebust if (block == NULL) 81ecdbf769STrond Myklebust return -EAGAIN; 821da177e4SLinus Torvalds 831da177e4SLinus Torvalds /* Go to sleep waiting for GRANT callback. Some servers seem 841da177e4SLinus Torvalds * to lose callbacks, however, so we're going to poll from 851da177e4SLinus Torvalds * time to time just to make sure. 861da177e4SLinus Torvalds * 871da177e4SLinus Torvalds * For now, the retry frequency is pretty high; normally 881da177e4SLinus Torvalds * a 1 minute timeout would do. See the comment before 891da177e4SLinus Torvalds * nlmclnt_lock for an explanation. 901da177e4SLinus Torvalds */ 91ecdbf769STrond Myklebust ret = wait_event_interruptible_timeout(block->b_wait, 92e8c5c045SAl Viro block->b_status != nlm_lck_blocked, 93ecdbf769STrond Myklebust timeout); 943a649b88STrond Myklebust if (ret < 0) 953a649b88STrond Myklebust return -ERESTARTSYS; 96ecdbf769STrond Myklebust req->a_res.status = block->b_status; 973a649b88STrond Myklebust return 0; 981da177e4SLinus Torvalds } 991da177e4SLinus Torvalds 1001da177e4SLinus Torvalds /* 1011da177e4SLinus Torvalds * The server lockd has called us back to tell us the lock was granted 1021da177e4SLinus Torvalds */ 10352921e02SAl Viro __be32 nlmclnt_grant(const struct sockaddr_in *addr, const struct nlm_lock *lock) 1041da177e4SLinus Torvalds { 1055ac5f9d1STrond Myklebust const struct file_lock *fl = &lock->fl; 1065ac5f9d1STrond Myklebust const struct nfs_fh *fh = &lock->fh; 1071da177e4SLinus Torvalds struct nlm_wait *block; 10852921e02SAl Viro __be32 res = nlm_lck_denied; 1091da177e4SLinus Torvalds 1101da177e4SLinus Torvalds /* 1111da177e4SLinus Torvalds * Look up blocked request based on arguments. 1121da177e4SLinus Torvalds * Warning: must not use cookie to match it! 1131da177e4SLinus Torvalds */ 1144f15e2b1STrond Myklebust list_for_each_entry(block, &nlm_blocked, b_list) { 1155ac5f9d1STrond Myklebust struct file_lock *fl_blocked = block->b_lock; 1165ac5f9d1STrond Myklebust 1177bab377fSTrond Myklebust if (fl_blocked->fl_start != fl->fl_start) 1187bab377fSTrond Myklebust continue; 1197bab377fSTrond Myklebust if (fl_blocked->fl_end != fl->fl_end) 1207bab377fSTrond Myklebust continue; 1217bab377fSTrond Myklebust /* 1227bab377fSTrond Myklebust * Careful! The NLM server will return the 32-bit "pid" that 1237bab377fSTrond Myklebust * we put on the wire: in this case the lockowner "pid". 1247bab377fSTrond Myklebust */ 1257bab377fSTrond Myklebust if (fl_blocked->fl_u.nfs_fl.owner->pid != lock->svid) 1265ac5f9d1STrond Myklebust continue; 1275ac5f9d1STrond Myklebust if (!nlm_cmp_addr(&block->b_host->h_addr, addr)) 1285ac5f9d1STrond Myklebust continue; 129225a719fSJosef Sipek if (nfs_compare_fh(NFS_FH(fl_blocked->fl_file->f_path.dentry->d_inode) ,fh) != 0) 1305ac5f9d1STrond Myklebust continue; 131ecdbf769STrond Myklebust /* Alright, we found a lock. Set the return status 132ecdbf769STrond Myklebust * and wake up the caller 1331da177e4SLinus Torvalds */ 134e8c5c045SAl Viro block->b_status = nlm_granted; 1351da177e4SLinus Torvalds wake_up(&block->b_wait); 136ecdbf769STrond Myklebust res = nlm_granted; 137ecdbf769STrond Myklebust } 138ecdbf769STrond Myklebust return res; 1391da177e4SLinus Torvalds } 1401da177e4SLinus Torvalds 1411da177e4SLinus Torvalds /* 1421da177e4SLinus Torvalds * The following procedures deal with the recovery of locks after a 1431da177e4SLinus Torvalds * server crash. 1441da177e4SLinus Torvalds */ 1451da177e4SLinus Torvalds 1461da177e4SLinus Torvalds /* 1471da177e4SLinus Torvalds * Reclaim all locks on server host. We do this by spawning a separate 1481da177e4SLinus Torvalds * reclaimer thread. 1491da177e4SLinus Torvalds */ 1501da177e4SLinus Torvalds void 1515c8dd29cSOlaf Kirch nlmclnt_recovery(struct nlm_host *host) 1521da177e4SLinus Torvalds { 15328df955aSTrond Myklebust if (!host->h_reclaiming++) { 1541da177e4SLinus Torvalds nlm_get_host(host); 1551da177e4SLinus Torvalds __module_get(THIS_MODULE); 156550facd1SOleg Nesterov if (kernel_thread(reclaimer, host, CLONE_FS | CLONE_FILES) < 0) 1571da177e4SLinus Torvalds module_put(THIS_MODULE); 1581da177e4SLinus Torvalds } 1591da177e4SLinus Torvalds } 1601da177e4SLinus Torvalds 1611da177e4SLinus Torvalds static int 1621da177e4SLinus Torvalds reclaimer(void *ptr) 1631da177e4SLinus Torvalds { 1641da177e4SLinus Torvalds struct nlm_host *host = (struct nlm_host *) ptr; 1651da177e4SLinus Torvalds struct nlm_wait *block; 16626bcbf96SChristoph Hellwig struct file_lock *fl, *next; 16728df955aSTrond Myklebust u32 nsmstate; 1681da177e4SLinus Torvalds 1691da177e4SLinus Torvalds daemonize("%s-reclaim", host->h_name); 1701da177e4SLinus Torvalds allow_signal(SIGKILL); 1711da177e4SLinus Torvalds 1725c8dd29cSOlaf Kirch down_write(&host->h_rwsem); 1735c8dd29cSOlaf Kirch 1741da177e4SLinus Torvalds /* This one ensures that our parent doesn't terminate while the 1751da177e4SLinus Torvalds * reclaim is in progress */ 1761da177e4SLinus Torvalds lock_kernel(); 1774a3ae42dSNeilBrown lockd_up(0); /* note: this cannot fail as lockd is already running */ 1781da177e4SLinus Torvalds 179d019bcf0SAdrian Bunk dprintk("lockd: reclaiming locks for host %s\n", host->h_name); 1805c8dd29cSOlaf Kirch 1811da177e4SLinus Torvalds restart: 18228df955aSTrond Myklebust nsmstate = host->h_nsmstate; 1835c8dd29cSOlaf Kirch 1845c8dd29cSOlaf Kirch /* Force a portmap getport - the peer's lockd will 1855c8dd29cSOlaf Kirch * most likely end up on a different port. 1865c8dd29cSOlaf Kirch */ 1870ade060eSOlaf Kirch host->h_nextrebind = jiffies; 1885c8dd29cSOlaf Kirch nlm_rebind_host(host); 1895c8dd29cSOlaf Kirch 1905c8dd29cSOlaf Kirch /* First, reclaim all locks that have been granted. */ 1915c8dd29cSOlaf Kirch list_splice_init(&host->h_granted, &host->h_reclaim); 19226bcbf96SChristoph Hellwig list_for_each_entry_safe(fl, next, &host->h_reclaim, fl_u.nfs_fl.list) { 1934c060b53STrond Myklebust list_del_init(&fl->fl_u.nfs_fl.list); 1941da177e4SLinus Torvalds 1955c8dd29cSOlaf Kirch /* Why are we leaking memory here? --okir */ 1961da177e4SLinus Torvalds if (signalled()) 1974c060b53STrond Myklebust continue; 19828df955aSTrond Myklebust if (nlmclnt_reclaim(host, fl) != 0) 19928df955aSTrond Myklebust continue; 2004c060b53STrond Myklebust list_add_tail(&fl->fl_u.nfs_fl.list, &host->h_granted); 20128df955aSTrond Myklebust if (host->h_nsmstate != nsmstate) { 20228df955aSTrond Myklebust /* Argh! The server rebooted again! */ 2031da177e4SLinus Torvalds goto restart; 2041da177e4SLinus Torvalds } 20528df955aSTrond Myklebust } 2065c8dd29cSOlaf Kirch 2075c8dd29cSOlaf Kirch host->h_reclaiming = 0; 2085c8dd29cSOlaf Kirch up_write(&host->h_rwsem); 209d019bcf0SAdrian Bunk dprintk("NLM: done reclaiming locks for host %s\n", host->h_name); 2101da177e4SLinus Torvalds 2111da177e4SLinus Torvalds /* Now, wake up all processes that sleep on a blocked lock */ 2124f15e2b1STrond Myklebust list_for_each_entry(block, &nlm_blocked, b_list) { 2131da177e4SLinus Torvalds if (block->b_host == host) { 214e8c5c045SAl Viro block->b_status = nlm_lck_denied_grace_period; 2151da177e4SLinus Torvalds wake_up(&block->b_wait); 2161da177e4SLinus Torvalds } 2171da177e4SLinus Torvalds } 2181da177e4SLinus Torvalds 2191da177e4SLinus Torvalds /* Release host handle after use */ 2201da177e4SLinus Torvalds nlm_release_host(host); 2211da177e4SLinus Torvalds lockd_down(); 2221da177e4SLinus Torvalds unlock_kernel(); 2231da177e4SLinus Torvalds module_put_and_exit(0); 2241da177e4SLinus Torvalds } 225