static int reclaimer(void *ptr) { struct nlm_host *host = (struct nlm_host *) ptr; struct nlm_wait *block; struct list_head *tmp; /* This one ensures that our parent doesn't terminate while the * reclaim is in progress */ lock_kernel(); lockd_up(); /* First, reclaim all locks that have been granted previously. */ restart: tmp = file_lock_list.next; while (tmp != &file_lock_list) { struct file_lock *fl = list_entry(tmp, struct file_lock, fl_link); struct inode *inode = fl->fl_file->f_dentry->d_inode; if (inode->i_sb->s_magic == NFS_SUPER_MAGIC && nlm_cmp_addr(NFS_ADDR(inode), &host->h_addr) && fl->fl_u.nfs_fl.state != host->h_state && (fl->fl_u.nfs_fl.flags & NFS_LCK_GRANTED)) { fl->fl_u.nfs_fl.flags &= ~ NFS_LCK_GRANTED; nlmclnt_reclaim(host, fl); /* This sleeps */ goto restart; } tmp = tmp->next; } host->h_reclaiming = 0; wake_up(&host->h_gracewait); /* Now, wake up all processes that sleep on a blocked lock */ for (block = nlm_blocked; block; block = block->b_next) { if (block->b_host == host) { block->b_status = NLM_LCK_DENIED_GRACE_PERIOD; wake_up(&block->b_wait); } } /* Release host handle after use */ nlm_release_host(host); lockd_down(); unlock_kernel(); return 0; }
/* * This is the main entry point for the NLM client. */ int nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl) { struct nfs_server *nfssrv = NFS_SERVER(inode); struct nlm_host *host; struct nlm_rqst reqst, *call = &reqst; sigset_t oldset; unsigned long flags; int status; /* Always use NLM version 1 over UDP for now... */ if (!(host = nlmclnt_lookup_host(NFS_ADDR(inode), IPPROTO_UDP, 1))) return -ENOLCK; /* Create RPC client handle if not there, and copy soft * and intr flags from NFS client. */ if (host->h_rpcclnt == NULL) { struct rpc_clnt *clnt; /* Bind an rpc client to this host handle (does not * perform a portmapper lookup) */ if (!(clnt = nlm_bind_host(host))) { status = -ENOLCK; goto done; } clnt->cl_softrtry = nfssrv->client->cl_softrtry; clnt->cl_intr = nfssrv->client->cl_intr; clnt->cl_chatty = nfssrv->client->cl_chatty; } /* Keep the old signal mask */ spin_lock_irqsave(¤t->sigmask_lock, flags); oldset = current->blocked; /* If we're cleaning up locks because the process is exiting, * perform the RPC call asynchronously. */ if ((cmd == F_SETLK || cmd == F_SETLKW) && fl->fl_type == F_UNLCK && (current->flags & PF_EXITING)) { sigfillset(¤t->blocked); /* Mask all signals */ recalc_sigpending(current); spin_unlock_irqrestore(¤t->sigmask_lock, flags); call = nlmclnt_alloc_call(); call->a_flags = RPC_TASK_ASYNC; } else { spin_unlock_irqrestore(¤t->sigmask_lock, flags); call->a_flags = 0; } call->a_host = host; /* Set up the argument struct */ nlmclnt_setlockargs(call, fl); if (cmd == F_GETLK) { status = nlmclnt_test(call, fl); } else if ((cmd == F_SETLK || cmd == F_SETLKW) && fl->fl_type == F_UNLCK) { status = nlmclnt_unlock(call, fl); } else if (cmd == F_SETLK || cmd == F_SETLKW) { call->a_args.block = (cmd == F_SETLKW)? 1 : 0; status = nlmclnt_lock(call, fl); } else { status = -EINVAL; } if (status < 0 && (call->a_flags & RPC_TASK_ASYNC)) rpc_free(call); spin_lock_irqsave(¤t->sigmask_lock, flags); current->blocked = oldset; recalc_sigpending(current); spin_unlock_irqrestore(¤t->sigmask_lock, flags); done: dprintk("lockd: clnt proc returns %d\n", status); nlm_release_host(host); return status; }
/* * This is the main entry point for the NLM client. */ int nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl) { struct nfs_server *nfssrv = NFS_SERVER(inode); struct nlm_host *host; struct nlm_rqst reqst, *call = &reqst; sigset_t oldset; unsigned long flags; int status, proto, vers; vers = (NFS_PROTO(inode)->version == 3) ? 4 : 1; if (NFS_PROTO(inode)->version > 3) { printk(KERN_NOTICE "NFSv4 file locking not implemented!\n"); return -ENOLCK; } /* Retrieve transport protocol from NFS client */ proto = NFS_CLIENT(inode)->cl_xprt->prot; if (!(host = nlmclnt_lookup_host(NFS_ADDR(inode), proto, vers))) return -ENOLCK; /* Create RPC client handle if not there, and copy soft * and intr flags from NFS client. */ if (host->h_rpcclnt == NULL) { struct rpc_clnt *clnt; /* Bind an rpc client to this host handle (does not * perform a portmapper lookup) */ if (!(clnt = nlm_bind_host(host))) { status = -ENOLCK; goto done; } clnt->cl_softrtry = nfssrv->client->cl_softrtry; clnt->cl_intr = nfssrv->client->cl_intr; clnt->cl_chatty = nfssrv->client->cl_chatty; } /* Keep the old signal mask */ spin_lock_irqsave(¤t->sighand->siglock, flags); oldset = current->blocked; /* If we're cleaning up locks because the process is exiting, * perform the RPC call asynchronously. */ if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) && fl->fl_type == F_UNLCK && (current->flags & PF_EXITING)) { sigfillset(¤t->blocked); /* Mask all signals */ recalc_sigpending(); spin_unlock_irqrestore(¤t->sighand->siglock, flags); call = nlmclnt_alloc_call(); if (!call) { status = -ENOMEM; goto out_restore; } call->a_flags = RPC_TASK_ASYNC; } else { spin_unlock_irqrestore(¤t->sighand->siglock, flags); memset(call, 0, sizeof(*call)); locks_init_lock(&call->a_args.lock.fl); locks_init_lock(&call->a_res.lock.fl); } call->a_host = host; /* Set up the argument struct */ nlmclnt_setlockargs(call, fl); if (IS_SETLK(cmd) || IS_SETLKW(cmd)) { if (fl->fl_type != F_UNLCK) { call->a_args.block = IS_SETLKW(cmd) ? 1 : 0; status = nlmclnt_lock(call, fl); } else status = nlmclnt_unlock(call, fl); } else if (IS_GETLK(cmd)) status = nlmclnt_test(call, fl); else status = -EINVAL; if (status < 0 && (call->a_flags & RPC_TASK_ASYNC)) kfree(call); out_restore: spin_lock_irqsave(¤t->sighand->siglock, flags); current->blocked = oldset; recalc_sigpending(); spin_unlock_irqrestore(¤t->sighand->siglock, flags); done: dprintk("lockd: clnt proc returns %d\n", status); nlm_release_host(host); return status; }