1ce0e08e2SPeter Avalos /*
2ce0e08e2SPeter Avalos * Copyright (c) 2000 Manuel Bouyer.
3ce0e08e2SPeter Avalos *
4ce0e08e2SPeter Avalos * Redistribution and use in source and binary forms, with or without
5ce0e08e2SPeter Avalos * modification, are permitted provided that the following conditions
6ce0e08e2SPeter Avalos * are met:
7ce0e08e2SPeter Avalos * 1. Redistributions of source code must retain the above copyright
8ce0e08e2SPeter Avalos * notice, this list of conditions and the following disclaimer.
9ce0e08e2SPeter Avalos * 2. Redistributions in binary form must reproduce the above copyright
10ce0e08e2SPeter Avalos * notice, this list of conditions and the following disclaimer in the
11ce0e08e2SPeter Avalos * documentation and/or other materials provided with the distribution.
12dc71b7abSJustin C. Sherrill * 3. Neither the name of the University nor the names of its contributors
13ce0e08e2SPeter Avalos * may be used to endorse or promote products derived from this software
14ce0e08e2SPeter Avalos * without specific prior written permission.
15ce0e08e2SPeter Avalos *
16ce0e08e2SPeter Avalos * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
17ce0e08e2SPeter Avalos * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18ce0e08e2SPeter Avalos * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19ce0e08e2SPeter Avalos * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
20ce0e08e2SPeter Avalos * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21ce0e08e2SPeter Avalos * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22ce0e08e2SPeter Avalos * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23ce0e08e2SPeter Avalos * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24ce0e08e2SPeter Avalos * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25ce0e08e2SPeter Avalos * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26ce0e08e2SPeter Avalos * SUCH DAMAGE.
27ce0e08e2SPeter Avalos *
28ce0e08e2SPeter Avalos * $NetBSD: lockd_lock.c,v 1.5 2000/11/21 03:47:41 enami Exp $
29ce0e08e2SPeter Avalos * $FreeBSD: src/usr.sbin/rpc.lockd/lockd_lock.c,v 1.1 2001/03/19 12:50:09 alfred Exp $
30ce0e08e2SPeter Avalos */
31ce0e08e2SPeter Avalos
32ce0e08e2SPeter Avalos #include <stdio.h>
33ce0e08e2SPeter Avalos #include <stdlib.h>
34ce0e08e2SPeter Avalos #include <unistd.h>
35ce0e08e2SPeter Avalos #include <fcntl.h>
36ce0e08e2SPeter Avalos #include <syslog.h>
37ce0e08e2SPeter Avalos #include <errno.h>
38ce0e08e2SPeter Avalos #include <string.h>
39ce0e08e2SPeter Avalos #include <signal.h>
40ce0e08e2SPeter Avalos #include <rpc/rpc.h>
41ce0e08e2SPeter Avalos #include <sys/types.h>
42ce0e08e2SPeter Avalos #include <sys/stat.h>
43ce0e08e2SPeter Avalos #include <sys/socket.h>
44ce0e08e2SPeter Avalos #include <sys/queue.h>
45ce0e08e2SPeter Avalos #include <sys/param.h>
46ce0e08e2SPeter Avalos #include <sys/mount.h>
47ce0e08e2SPeter Avalos #include <sys/wait.h>
48ce0e08e2SPeter Avalos #include <rpcsvc/sm_inter.h>
49ce0e08e2SPeter Avalos #include <rpcsvc/nlm_prot.h>
50ce0e08e2SPeter Avalos #include "lockd_lock.h"
51ce0e08e2SPeter Avalos #include "lockd.h"
52ce0e08e2SPeter Avalos
53ce0e08e2SPeter Avalos /* A set of utilities for managing file locking */
54ce0e08e2SPeter Avalos LIST_HEAD(lcklst_head, file_lock);
55ce0e08e2SPeter Avalos struct lcklst_head lcklst_head = LIST_HEAD_INITIALIZER(lcklst_head);
56ce0e08e2SPeter Avalos
57ce0e08e2SPeter Avalos /* struct describing a lock */
58ce0e08e2SPeter Avalos struct file_lock {
59ce0e08e2SPeter Avalos LIST_ENTRY(file_lock) lcklst;
60ce0e08e2SPeter Avalos fhandle_t filehandle; /* NFS filehandle */
61ce0e08e2SPeter Avalos struct sockaddr *addr;
62ce0e08e2SPeter Avalos struct nlm4_holder client; /* lock holder */
63ce0e08e2SPeter Avalos netobj client_cookie; /* cookie sent by the client */
64ce0e08e2SPeter Avalos char client_name[128];
65ce0e08e2SPeter Avalos int nsm_status; /* status from the remote lock manager */
66ce0e08e2SPeter Avalos int status; /* lock status, see below */
67ce0e08e2SPeter Avalos int flags; /* lock flags, see lockd_lock.h */
68ce0e08e2SPeter Avalos pid_t locker; /* pid of the child process trying to get the lock */
69ce0e08e2SPeter Avalos int fd; /* file descriptor for this lock */
70ce0e08e2SPeter Avalos };
71ce0e08e2SPeter Avalos
72ce0e08e2SPeter Avalos /* lock status */
73ce0e08e2SPeter Avalos #define LKST_LOCKED 1 /* lock is locked */
74ce0e08e2SPeter Avalos #define LKST_WAITING 2 /* file is already locked by another host */
7524c80b2bSSascha Wildner #define LKST_PROCESSING 3 /* child is trying to acquire the lock */
76ce0e08e2SPeter Avalos #define LKST_DYING 4 /* must dies when we get news from the child */
77ce0e08e2SPeter Avalos
78ce0e08e2SPeter Avalos void lfree(struct file_lock *);
7921eb4b7eSSascha Wildner void sigchild_handler(int);
80ce0e08e2SPeter Avalos enum nlm_stats do_lock(struct file_lock *, int);
81ce0e08e2SPeter Avalos enum nlm_stats do_unlock(struct file_lock *);
82ce0e08e2SPeter Avalos void send_granted(struct file_lock *, int);
83ce0e08e2SPeter Avalos void siglock(void);
84ce0e08e2SPeter Avalos void sigunlock(void);
85ce0e08e2SPeter Avalos
86ce0e08e2SPeter Avalos /* list of hosts we monitor */
87ce0e08e2SPeter Avalos LIST_HEAD(hostlst_head, host);
88ce0e08e2SPeter Avalos struct hostlst_head hostlst_head = LIST_HEAD_INITIALIZER(hostlst_head);
89ce0e08e2SPeter Avalos
90ce0e08e2SPeter Avalos /* struct describing a lock */
91ce0e08e2SPeter Avalos struct host {
92ce0e08e2SPeter Avalos LIST_ENTRY(host) hostlst;
93ce0e08e2SPeter Avalos char name[SM_MAXSTRLEN];
94ce0e08e2SPeter Avalos int refcnt;
95ce0e08e2SPeter Avalos };
96ce0e08e2SPeter Avalos
97ce0e08e2SPeter Avalos void do_mon(char *);
98ce0e08e2SPeter Avalos
99ce0e08e2SPeter Avalos /*
100ce0e08e2SPeter Avalos * testlock(): inform the caller if the requested lock would be granted or not
101ce0e08e2SPeter Avalos * returns NULL if lock would granted, or pointer to the current nlm4_holder
102ce0e08e2SPeter Avalos * otherwise.
103ce0e08e2SPeter Avalos */
104ce0e08e2SPeter Avalos
105ce0e08e2SPeter Avalos struct nlm4_holder *
testlock(struct nlm4_lock * lock,int flags)106ce0e08e2SPeter Avalos testlock(struct nlm4_lock *lock, int flags)
107ce0e08e2SPeter Avalos {
108ce0e08e2SPeter Avalos struct file_lock *fl;
109ce0e08e2SPeter Avalos fhandle_t filehandle;
110ce0e08e2SPeter Avalos
111ce0e08e2SPeter Avalos /* convert lock to a local filehandle */
112ce0e08e2SPeter Avalos memcpy(&filehandle, lock->fh.n_bytes, sizeof(filehandle));
113ce0e08e2SPeter Avalos
114ce0e08e2SPeter Avalos siglock();
115ce0e08e2SPeter Avalos /* search through the list for lock holder */
116ce0e08e2SPeter Avalos for (fl = LIST_FIRST(&lcklst_head); fl != NULL;
117ce0e08e2SPeter Avalos fl = LIST_NEXT(fl, lcklst)) {
118ce0e08e2SPeter Avalos if (fl->status != LKST_LOCKED)
119ce0e08e2SPeter Avalos continue;
120ce0e08e2SPeter Avalos if (memcmp(&fl->filehandle, &filehandle, sizeof(filehandle)))
121ce0e08e2SPeter Avalos continue;
122ce0e08e2SPeter Avalos /* got it ! */
123ce0e08e2SPeter Avalos syslog(LOG_DEBUG, "test for %s: found lock held by %s",
124ce0e08e2SPeter Avalos lock->caller_name, fl->client_name);
125ce0e08e2SPeter Avalos sigunlock();
126ce0e08e2SPeter Avalos return (&fl->client);
127ce0e08e2SPeter Avalos }
128ce0e08e2SPeter Avalos /* not found */
129ce0e08e2SPeter Avalos sigunlock();
130ce0e08e2SPeter Avalos syslog(LOG_DEBUG, "test for %s: no lock found", lock->caller_name);
131ce0e08e2SPeter Avalos return NULL;
132ce0e08e2SPeter Avalos }
133ce0e08e2SPeter Avalos
134ce0e08e2SPeter Avalos /*
13524c80b2bSSascha Wildner * getlock: try to acquire the lock.
136ce0e08e2SPeter Avalos * If file is already locked and we can sleep, put the lock in the list with
137ce0e08e2SPeter Avalos * status LKST_WAITING; it'll be processed later.
138ce0e08e2SPeter Avalos * Otherwise try to lock. If we're allowed to block, fork a child which
139ce0e08e2SPeter Avalos * will do the blocking lock.
140ce0e08e2SPeter Avalos */
141ce0e08e2SPeter Avalos enum nlm_stats
getlock(nlm4_lockargs * lckarg,struct svc_req * rqstp,int flags)142ce0e08e2SPeter Avalos getlock(nlm4_lockargs *lckarg, struct svc_req *rqstp, int flags)
143ce0e08e2SPeter Avalos {
144ce0e08e2SPeter Avalos struct file_lock *fl, *newfl;
145ce0e08e2SPeter Avalos enum nlm_stats retval;
146ce0e08e2SPeter Avalos
147ce0e08e2SPeter Avalos if (grace_expired == 0 && lckarg->reclaim == 0)
148ce0e08e2SPeter Avalos return (flags & LOCK_V4) ?
149ce0e08e2SPeter Avalos nlm4_denied_grace_period : nlm_denied_grace_period;
150ce0e08e2SPeter Avalos
151ce0e08e2SPeter Avalos /* allocate new file_lock for this request */
152ce0e08e2SPeter Avalos newfl = malloc(sizeof(struct file_lock));
153ce0e08e2SPeter Avalos if (newfl == NULL) {
154ce0e08e2SPeter Avalos syslog(LOG_NOTICE, "malloc failed: %s", strerror(errno));
155ce0e08e2SPeter Avalos /* failed */
156ce0e08e2SPeter Avalos return (flags & LOCK_V4) ?
157ce0e08e2SPeter Avalos nlm4_denied_nolock : nlm_denied_nolocks;
158ce0e08e2SPeter Avalos }
159ce0e08e2SPeter Avalos if (lckarg->alock.fh.n_len != sizeof(fhandle_t)) {
1606b882c34SSascha Wildner syslog(LOG_DEBUG, "received fhandle size %d, local size %d",
161ce0e08e2SPeter Avalos lckarg->alock.fh.n_len, (int)sizeof(fhandle_t));
162ce0e08e2SPeter Avalos }
163ce0e08e2SPeter Avalos memcpy(&newfl->filehandle, lckarg->alock.fh.n_bytes, sizeof(fhandle_t));
164ce0e08e2SPeter Avalos newfl->addr = (struct sockaddr *)svc_getrpccaller(rqstp->rq_xprt)->buf;
165ce0e08e2SPeter Avalos newfl->client.exclusive = lckarg->exclusive;
166ce0e08e2SPeter Avalos newfl->client.svid = lckarg->alock.svid;
167ce0e08e2SPeter Avalos newfl->client.oh.n_bytes = malloc(lckarg->alock.oh.n_len);
168ce0e08e2SPeter Avalos if (newfl->client.oh.n_bytes == NULL) {
169ce0e08e2SPeter Avalos syslog(LOG_NOTICE, "malloc failed: %s", strerror(errno));
170ce0e08e2SPeter Avalos free(newfl);
171ce0e08e2SPeter Avalos return (flags & LOCK_V4) ?
172ce0e08e2SPeter Avalos nlm4_denied_nolock : nlm_denied_nolocks;
173ce0e08e2SPeter Avalos }
174ce0e08e2SPeter Avalos newfl->client.oh.n_len = lckarg->alock.oh.n_len;
175ce0e08e2SPeter Avalos memcpy(newfl->client.oh.n_bytes, lckarg->alock.oh.n_bytes,
176ce0e08e2SPeter Avalos lckarg->alock.oh.n_len);
177ce0e08e2SPeter Avalos newfl->client.l_offset = lckarg->alock.l_offset;
178ce0e08e2SPeter Avalos newfl->client.l_len = lckarg->alock.l_len;
179ce0e08e2SPeter Avalos newfl->client_cookie.n_len = lckarg->cookie.n_len;
180ce0e08e2SPeter Avalos newfl->client_cookie.n_bytes = malloc(lckarg->cookie.n_len);
181ce0e08e2SPeter Avalos if (newfl->client_cookie.n_bytes == NULL) {
182ce0e08e2SPeter Avalos syslog(LOG_NOTICE, "malloc failed: %s", strerror(errno));
183ce0e08e2SPeter Avalos free(newfl->client.oh.n_bytes);
184ce0e08e2SPeter Avalos free(newfl);
185ce0e08e2SPeter Avalos return (flags & LOCK_V4) ?
186ce0e08e2SPeter Avalos nlm4_denied_nolock : nlm_denied_nolocks;
187ce0e08e2SPeter Avalos }
188ce0e08e2SPeter Avalos memcpy(newfl->client_cookie.n_bytes, lckarg->cookie.n_bytes,
189ce0e08e2SPeter Avalos lckarg->cookie.n_len);
190ce0e08e2SPeter Avalos strncpy(newfl->client_name, lckarg->alock.caller_name, 128);
191ce0e08e2SPeter Avalos newfl->nsm_status = lckarg->state;
192ce0e08e2SPeter Avalos newfl->status = 0;
193ce0e08e2SPeter Avalos newfl->flags = flags;
194ce0e08e2SPeter Avalos siglock();
195ce0e08e2SPeter Avalos /* look for a lock rq from this host for this fh */
196ce0e08e2SPeter Avalos for (fl = LIST_FIRST(&lcklst_head); fl != NULL;
197ce0e08e2SPeter Avalos fl = LIST_NEXT(fl, lcklst)) {
198ce0e08e2SPeter Avalos if (memcmp(&newfl->filehandle, &fl->filehandle,
199ce0e08e2SPeter Avalos sizeof(fhandle_t)) == 0) {
200ce0e08e2SPeter Avalos if (strcmp(newfl->client_name, fl->client_name) == 0 &&
201ce0e08e2SPeter Avalos newfl->client.svid == fl->client.svid) {
202ce0e08e2SPeter Avalos /* already locked by this host ??? */
203ce0e08e2SPeter Avalos sigunlock();
204ce0e08e2SPeter Avalos syslog(LOG_NOTICE, "duplicate lock from %s",
205ce0e08e2SPeter Avalos newfl->client_name);
206ce0e08e2SPeter Avalos lfree(newfl);
207ce0e08e2SPeter Avalos switch(fl->status) {
208ce0e08e2SPeter Avalos case LKST_LOCKED:
209ce0e08e2SPeter Avalos return (flags & LOCK_V4) ?
210ce0e08e2SPeter Avalos nlm4_granted : nlm_granted;
211ce0e08e2SPeter Avalos case LKST_WAITING:
212ce0e08e2SPeter Avalos case LKST_PROCESSING:
213ce0e08e2SPeter Avalos return (flags & LOCK_V4) ?
214ce0e08e2SPeter Avalos nlm4_blocked : nlm_blocked;
215ce0e08e2SPeter Avalos case LKST_DYING:
216ce0e08e2SPeter Avalos return (flags & LOCK_V4) ?
217ce0e08e2SPeter Avalos nlm4_denied : nlm_denied;
218ce0e08e2SPeter Avalos default:
219ce0e08e2SPeter Avalos syslog(LOG_NOTICE, "bad status %d",
220ce0e08e2SPeter Avalos fl->status);
221ce0e08e2SPeter Avalos return (flags & LOCK_V4) ?
222ce0e08e2SPeter Avalos nlm4_failed : nlm_denied;
223ce0e08e2SPeter Avalos }
224ce0e08e2SPeter Avalos }
225ce0e08e2SPeter Avalos /*
226ce0e08e2SPeter Avalos * We already have a lock for this file. Put this one
227ce0e08e2SPeter Avalos * in waiting state if allowed to block
228ce0e08e2SPeter Avalos */
229ce0e08e2SPeter Avalos if (lckarg->block) {
230ce0e08e2SPeter Avalos syslog(LOG_DEBUG, "lock from %s: already "
231ce0e08e2SPeter Avalos "locked, waiting",
232ce0e08e2SPeter Avalos lckarg->alock.caller_name);
233ce0e08e2SPeter Avalos newfl->status = LKST_WAITING;
234ce0e08e2SPeter Avalos LIST_INSERT_HEAD(&lcklst_head, newfl, lcklst);
235ce0e08e2SPeter Avalos do_mon(lckarg->alock.caller_name);
236ce0e08e2SPeter Avalos sigunlock();
237ce0e08e2SPeter Avalos return (flags & LOCK_V4) ?
238ce0e08e2SPeter Avalos nlm4_blocked : nlm_blocked;
239ce0e08e2SPeter Avalos } else {
240ce0e08e2SPeter Avalos sigunlock();
241ce0e08e2SPeter Avalos syslog(LOG_DEBUG, "lock from %s: already "
242ce0e08e2SPeter Avalos "locked, failed",
243ce0e08e2SPeter Avalos lckarg->alock.caller_name);
244ce0e08e2SPeter Avalos lfree(newfl);
245ce0e08e2SPeter Avalos return (flags & LOCK_V4) ?
246ce0e08e2SPeter Avalos nlm4_denied : nlm_denied;
247ce0e08e2SPeter Avalos }
248ce0e08e2SPeter Avalos }
249ce0e08e2SPeter Avalos }
250ce0e08e2SPeter Avalos /* no entry for this file yet; add to list */
251ce0e08e2SPeter Avalos LIST_INSERT_HEAD(&lcklst_head, newfl, lcklst);
252ce0e08e2SPeter Avalos /* do the lock */
253ce0e08e2SPeter Avalos retval = do_lock(newfl, lckarg->block);
254ce0e08e2SPeter Avalos switch (retval) {
255ce0e08e2SPeter Avalos case nlm4_granted:
256ce0e08e2SPeter Avalos /* case nlm_granted: is the same as nlm4_granted */
257ce0e08e2SPeter Avalos case nlm4_blocked:
258ce0e08e2SPeter Avalos /* case nlm_blocked: is the same as nlm4_blocked */
259ce0e08e2SPeter Avalos do_mon(lckarg->alock.caller_name);
260ce0e08e2SPeter Avalos break;
261ce0e08e2SPeter Avalos default:
262ce0e08e2SPeter Avalos lfree(newfl);
263ce0e08e2SPeter Avalos break;
264ce0e08e2SPeter Avalos }
265ce0e08e2SPeter Avalos sigunlock();
266ce0e08e2SPeter Avalos return retval;
267ce0e08e2SPeter Avalos }
268ce0e08e2SPeter Avalos
269ce0e08e2SPeter Avalos /* unlock a filehandle */
270ce0e08e2SPeter Avalos enum nlm_stats
unlock(nlm4_lock * lck,int flags)271ce0e08e2SPeter Avalos unlock(nlm4_lock *lck, int flags)
272ce0e08e2SPeter Avalos {
273ce0e08e2SPeter Avalos struct file_lock *fl;
274ce0e08e2SPeter Avalos fhandle_t filehandle;
275ce0e08e2SPeter Avalos int err = (flags & LOCK_V4) ? nlm4_granted : nlm_granted;
276ce0e08e2SPeter Avalos
277ce0e08e2SPeter Avalos memcpy(&filehandle, lck->fh.n_bytes, sizeof(fhandle_t));
278ce0e08e2SPeter Avalos siglock();
279ce0e08e2SPeter Avalos for (fl = LIST_FIRST(&lcklst_head); fl != NULL;
280ce0e08e2SPeter Avalos fl = LIST_NEXT(fl, lcklst)) {
281ce0e08e2SPeter Avalos if (strcmp(fl->client_name, lck->caller_name) ||
282ce0e08e2SPeter Avalos memcmp(&filehandle, &fl->filehandle, sizeof(fhandle_t)) ||
283ce0e08e2SPeter Avalos fl->client.oh.n_len != lck->oh.n_len ||
284ce0e08e2SPeter Avalos memcmp(fl->client.oh.n_bytes, lck->oh.n_bytes,
285ce0e08e2SPeter Avalos fl->client.oh.n_len) != 0 ||
286ce0e08e2SPeter Avalos fl->client.svid != lck->svid)
287ce0e08e2SPeter Avalos continue;
288ce0e08e2SPeter Avalos /* Got it, unlock and remove from the queue */
289ce0e08e2SPeter Avalos syslog(LOG_DEBUG, "unlock from %s: found struct, status %d",
290ce0e08e2SPeter Avalos lck->caller_name, fl->status);
291ce0e08e2SPeter Avalos switch (fl->status) {
292ce0e08e2SPeter Avalos case LKST_LOCKED:
293ce0e08e2SPeter Avalos err = do_unlock(fl);
294ce0e08e2SPeter Avalos break;
295ce0e08e2SPeter Avalos case LKST_WAITING:
296ce0e08e2SPeter Avalos /* remove from the list */
297ce0e08e2SPeter Avalos LIST_REMOVE(fl, lcklst);
298ce0e08e2SPeter Avalos lfree(fl);
299ce0e08e2SPeter Avalos break;
300ce0e08e2SPeter Avalos case LKST_PROCESSING:
301ce0e08e2SPeter Avalos /*
302ce0e08e2SPeter Avalos * being handled by a child; will clean up
303ce0e08e2SPeter Avalos * when the child exits
304ce0e08e2SPeter Avalos */
305ce0e08e2SPeter Avalos fl->status = LKST_DYING;
306ce0e08e2SPeter Avalos break;
307ce0e08e2SPeter Avalos case LKST_DYING:
308ce0e08e2SPeter Avalos /* nothing to do */
309ce0e08e2SPeter Avalos break;
310ce0e08e2SPeter Avalos default:
31195cdd875SSascha Wildner syslog(LOG_NOTICE, "unknown status %d for %s",
312ce0e08e2SPeter Avalos fl->status, fl->client_name);
313ce0e08e2SPeter Avalos }
314ce0e08e2SPeter Avalos sigunlock();
315ce0e08e2SPeter Avalos return err;
316ce0e08e2SPeter Avalos }
317ce0e08e2SPeter Avalos sigunlock();
318ce0e08e2SPeter Avalos /* didn't find a matching entry; log anyway */
319ce0e08e2SPeter Avalos syslog(LOG_NOTICE, "no matching entry for %s",
320ce0e08e2SPeter Avalos lck->caller_name);
321ce0e08e2SPeter Avalos return (flags & LOCK_V4) ? nlm4_granted : nlm_granted;
322ce0e08e2SPeter Avalos }
323ce0e08e2SPeter Avalos
324ce0e08e2SPeter Avalos void
lfree(struct file_lock * fl)325ce0e08e2SPeter Avalos lfree(struct file_lock *fl)
326ce0e08e2SPeter Avalos {
327ce0e08e2SPeter Avalos free(fl->client.oh.n_bytes);
328ce0e08e2SPeter Avalos free(fl->client_cookie.n_bytes);
329ce0e08e2SPeter Avalos free(fl);
330ce0e08e2SPeter Avalos }
331ce0e08e2SPeter Avalos
332ce0e08e2SPeter Avalos void
sigchild_handler(int sig)333ce0e08e2SPeter Avalos sigchild_handler(int sig)
334ce0e08e2SPeter Avalos {
335ce0e08e2SPeter Avalos int status;
336ce0e08e2SPeter Avalos pid_t pid;
337ce0e08e2SPeter Avalos struct file_lock *fl;
338ce0e08e2SPeter Avalos
339ce0e08e2SPeter Avalos while (1) {
340ce0e08e2SPeter Avalos pid = wait4(-1, &status, WNOHANG, NULL);
341ce0e08e2SPeter Avalos if (pid == -1) {
342ce0e08e2SPeter Avalos if (errno != ECHILD)
343ce0e08e2SPeter Avalos syslog(LOG_NOTICE, "wait failed: %s",
344ce0e08e2SPeter Avalos strerror(errno));
345ce0e08e2SPeter Avalos else
346ce0e08e2SPeter Avalos syslog(LOG_DEBUG, "wait failed: %s",
347ce0e08e2SPeter Avalos strerror(errno));
348ce0e08e2SPeter Avalos return;
349ce0e08e2SPeter Avalos }
350ce0e08e2SPeter Avalos if (pid == 0) {
351ce0e08e2SPeter Avalos /* no more child to handle yet */
352ce0e08e2SPeter Avalos return;
353ce0e08e2SPeter Avalos }
354ce0e08e2SPeter Avalos /*
355ce0e08e2SPeter Avalos * if we're here we have a child that exited
356ce0e08e2SPeter Avalos * Find the associated file_lock.
357ce0e08e2SPeter Avalos */
358ce0e08e2SPeter Avalos for (fl = LIST_FIRST(&lcklst_head); fl != NULL;
359ce0e08e2SPeter Avalos fl = LIST_NEXT(fl, lcklst)) {
360ce0e08e2SPeter Avalos if (pid == fl->locker)
361ce0e08e2SPeter Avalos break;
362ce0e08e2SPeter Avalos }
363ce0e08e2SPeter Avalos if (pid != fl->locker) {
36495cdd875SSascha Wildner syslog(LOG_NOTICE, "unknown child %d", pid);
365ce0e08e2SPeter Avalos } else {
366ce0e08e2SPeter Avalos if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
367ce0e08e2SPeter Avalos syslog(LOG_NOTICE, "child %d failed", pid);
368ce0e08e2SPeter Avalos /*
369ce0e08e2SPeter Avalos * can't do much here; we can't reply
370ce0e08e2SPeter Avalos * anything but OK for blocked locks
371ce0e08e2SPeter Avalos * Eventually the client will time out
372ce0e08e2SPeter Avalos * and retry.
373ce0e08e2SPeter Avalos */
374ce0e08e2SPeter Avalos do_unlock(fl);
375ce0e08e2SPeter Avalos return;
376ce0e08e2SPeter Avalos }
377ce0e08e2SPeter Avalos
378ce0e08e2SPeter Avalos /* check lock status */
379ce0e08e2SPeter Avalos syslog(LOG_DEBUG, "processing child %d, status %d",
380ce0e08e2SPeter Avalos pid, fl->status);
381ce0e08e2SPeter Avalos switch(fl->status) {
382ce0e08e2SPeter Avalos case LKST_PROCESSING:
383ce0e08e2SPeter Avalos fl->status = LKST_LOCKED;
384ce0e08e2SPeter Avalos send_granted(fl, (fl->flags & LOCK_V4) ?
385ce0e08e2SPeter Avalos nlm4_granted : nlm_granted);
386ce0e08e2SPeter Avalos break;
387ce0e08e2SPeter Avalos case LKST_DYING:
388ce0e08e2SPeter Avalos do_unlock(fl);
389ce0e08e2SPeter Avalos break;
390ce0e08e2SPeter Avalos default:
391ce0e08e2SPeter Avalos syslog(LOG_NOTICE, "bad lock status (%d) for"
392ce0e08e2SPeter Avalos " child %d", fl->status, pid);
393ce0e08e2SPeter Avalos }
394ce0e08e2SPeter Avalos }
395ce0e08e2SPeter Avalos }
396ce0e08e2SPeter Avalos }
397ce0e08e2SPeter Avalos
398ce0e08e2SPeter Avalos /*
399ce0e08e2SPeter Avalos *
40024c80b2bSSascha Wildner * try to acquire the lock described by fl. Eventually fock a child to do a
401ce0e08e2SPeter Avalos * blocking lock if allowed and required.
402ce0e08e2SPeter Avalos */
403ce0e08e2SPeter Avalos
404ce0e08e2SPeter Avalos enum nlm_stats
do_lock(struct file_lock * fl,int block)405ce0e08e2SPeter Avalos do_lock(struct file_lock *fl, int block)
406ce0e08e2SPeter Avalos {
407ce0e08e2SPeter Avalos int lflags, error;
408ce0e08e2SPeter Avalos struct stat st;
409ce0e08e2SPeter Avalos
410ce0e08e2SPeter Avalos fl->fd = fhopen(&fl->filehandle, O_RDWR);
411ce0e08e2SPeter Avalos if (fl->fd < 0) {
412ce0e08e2SPeter Avalos switch (errno) {
413ce0e08e2SPeter Avalos case ESTALE:
414ce0e08e2SPeter Avalos error = nlm4_stale_fh;
415ce0e08e2SPeter Avalos break;
416ce0e08e2SPeter Avalos case EROFS:
417ce0e08e2SPeter Avalos error = nlm4_rofs;
418ce0e08e2SPeter Avalos break;
419ce0e08e2SPeter Avalos default:
420ce0e08e2SPeter Avalos error = nlm4_failed;
421ce0e08e2SPeter Avalos }
422ce0e08e2SPeter Avalos if ((fl->flags & LOCK_V4) == 0)
423ce0e08e2SPeter Avalos error = nlm_denied;
424ce0e08e2SPeter Avalos syslog(LOG_NOTICE, "fhopen failed (from %s): %s",
425ce0e08e2SPeter Avalos fl->client_name, strerror(errno));
426ce0e08e2SPeter Avalos LIST_REMOVE(fl, lcklst);
4273598cc14SSascha Wildner return error;
428ce0e08e2SPeter Avalos }
429ce0e08e2SPeter Avalos if (fstat(fl->fd, &st) < 0) {
430ce0e08e2SPeter Avalos syslog(LOG_NOTICE, "fstat failed (from %s): %s",
431ce0e08e2SPeter Avalos fl->client_name, strerror(errno));
432ce0e08e2SPeter Avalos }
43321eb4b7eSSascha Wildner syslog(LOG_DEBUG, "lock from %s for file%s%s: dev %d ino %ju (uid %d), "
434ce0e08e2SPeter Avalos "flags %d",
435ce0e08e2SPeter Avalos fl->client_name, fl->client.exclusive ? " (exclusive)":"",
436ce0e08e2SPeter Avalos block ? " (block)":"",
43721eb4b7eSSascha Wildner st.st_dev, (uintmax_t)st.st_ino, st.st_uid, fl->flags);
438ce0e08e2SPeter Avalos lflags = LOCK_NB;
439ce0e08e2SPeter Avalos if (fl->client.exclusive == 0)
440ce0e08e2SPeter Avalos lflags |= LOCK_SH;
441ce0e08e2SPeter Avalos else
442ce0e08e2SPeter Avalos lflags |= LOCK_EX;
443ce0e08e2SPeter Avalos error = flock(fl->fd, lflags);
444ce0e08e2SPeter Avalos if (error != 0 && errno == EAGAIN && block) {
445ce0e08e2SPeter Avalos switch (fl->locker = fork()) {
446ce0e08e2SPeter Avalos case -1: /* fork failed */
447ce0e08e2SPeter Avalos syslog(LOG_NOTICE, "fork failed: %s", strerror(errno));
448ce0e08e2SPeter Avalos LIST_REMOVE(fl, lcklst);
449ce0e08e2SPeter Avalos close(fl->fd);
450ce0e08e2SPeter Avalos return (fl->flags & LOCK_V4) ?
451ce0e08e2SPeter Avalos nlm4_denied_nolock : nlm_denied_nolocks;
452ce0e08e2SPeter Avalos case 0:
453ce0e08e2SPeter Avalos /*
454ce0e08e2SPeter Avalos * Attempt a blocking lock. Will have to call
455ce0e08e2SPeter Avalos * NLM_GRANTED later.
456ce0e08e2SPeter Avalos */
457ce0e08e2SPeter Avalos setproctitle("%s", fl->client_name);
458ce0e08e2SPeter Avalos lflags &= ~LOCK_NB;
459ce0e08e2SPeter Avalos if(flock(fl->fd, lflags) != 0) {
460ce0e08e2SPeter Avalos syslog(LOG_NOTICE, "flock failed: %s",
461ce0e08e2SPeter Avalos strerror(errno));
462ce0e08e2SPeter Avalos exit(-1);
463ce0e08e2SPeter Avalos }
464ce0e08e2SPeter Avalos /* lock granted */
465ce0e08e2SPeter Avalos exit(0);
466ce0e08e2SPeter Avalos default:
467ce0e08e2SPeter Avalos syslog(LOG_DEBUG, "lock request from %s: forked %d",
468ce0e08e2SPeter Avalos fl->client_name, fl->locker);
469ce0e08e2SPeter Avalos fl->status = LKST_PROCESSING;
470ce0e08e2SPeter Avalos return (fl->flags & LOCK_V4) ?
471ce0e08e2SPeter Avalos nlm4_blocked : nlm_blocked;
472ce0e08e2SPeter Avalos }
473ce0e08e2SPeter Avalos }
474ce0e08e2SPeter Avalos /* non block case */
475ce0e08e2SPeter Avalos if (error != 0) {
476ce0e08e2SPeter Avalos switch (errno) {
477ce0e08e2SPeter Avalos case EAGAIN:
478ce0e08e2SPeter Avalos error = nlm4_denied;
479ce0e08e2SPeter Avalos break;
480ce0e08e2SPeter Avalos case ESTALE:
481ce0e08e2SPeter Avalos error = nlm4_stale_fh;
482ce0e08e2SPeter Avalos break;
483ce0e08e2SPeter Avalos case EROFS:
484ce0e08e2SPeter Avalos error = nlm4_rofs;
485ce0e08e2SPeter Avalos break;
486ce0e08e2SPeter Avalos default:
487ce0e08e2SPeter Avalos error = nlm4_failed;
488ce0e08e2SPeter Avalos }
489ce0e08e2SPeter Avalos if ((fl->flags & LOCK_V4) == 0)
490ce0e08e2SPeter Avalos error = nlm_denied;
491ce0e08e2SPeter Avalos if (errno != EAGAIN)
492ce0e08e2SPeter Avalos syslog(LOG_NOTICE, "flock for %s failed: %s",
493ce0e08e2SPeter Avalos fl->client_name, strerror(errno));
494ce0e08e2SPeter Avalos else syslog(LOG_DEBUG, "flock for %s failed: %s",
495ce0e08e2SPeter Avalos fl->client_name, strerror(errno));
496ce0e08e2SPeter Avalos LIST_REMOVE(fl, lcklst);
497ce0e08e2SPeter Avalos close(fl->fd);
498ce0e08e2SPeter Avalos return error;
499ce0e08e2SPeter Avalos }
500ce0e08e2SPeter Avalos fl->status = LKST_LOCKED;
501ce0e08e2SPeter Avalos return (fl->flags & LOCK_V4) ? nlm4_granted : nlm_granted;
502ce0e08e2SPeter Avalos }
503ce0e08e2SPeter Avalos
504ce0e08e2SPeter Avalos void
send_granted(struct file_lock * fl,int opcode)505ce0e08e2SPeter Avalos send_granted(struct file_lock *fl, int opcode)
506ce0e08e2SPeter Avalos {
507ce0e08e2SPeter Avalos CLIENT *cli;
508ce0e08e2SPeter Avalos static char dummy;
509ce0e08e2SPeter Avalos struct timeval timeo;
510ce0e08e2SPeter Avalos int success;
511ce0e08e2SPeter Avalos static struct nlm_res retval;
512ce0e08e2SPeter Avalos static struct nlm4_res retval4;
513ce0e08e2SPeter Avalos
514ce0e08e2SPeter Avalos cli = get_client(fl->addr,
515ce0e08e2SPeter Avalos (fl->flags & LOCK_V4) ? NLM_VERS4 : NLM_VERS);
516ce0e08e2SPeter Avalos if (cli == NULL) {
517ce0e08e2SPeter Avalos syslog(LOG_NOTICE, "failed to get CLIENT for %s",
518ce0e08e2SPeter Avalos fl->client_name);
519ce0e08e2SPeter Avalos /*
520ce0e08e2SPeter Avalos * We fail to notify remote that the lock has been granted.
521ce0e08e2SPeter Avalos * The client will timeout and retry, the lock will be
522ce0e08e2SPeter Avalos * granted at this time.
523ce0e08e2SPeter Avalos */
524ce0e08e2SPeter Avalos return;
525ce0e08e2SPeter Avalos }
526ce0e08e2SPeter Avalos timeo.tv_sec = 0;
527ce0e08e2SPeter Avalos timeo.tv_usec = (fl->flags & LOCK_ASYNC) ? 0 : 500000; /* 0.5s */
528ce0e08e2SPeter Avalos
529ce0e08e2SPeter Avalos if (fl->flags & LOCK_V4) {
530ce0e08e2SPeter Avalos static nlm4_testargs res;
531ce0e08e2SPeter Avalos res.cookie = fl->client_cookie;
532ce0e08e2SPeter Avalos res.exclusive = fl->client.exclusive;
533ce0e08e2SPeter Avalos res.alock.caller_name = fl->client_name;
534ce0e08e2SPeter Avalos res.alock.fh.n_len = sizeof(fhandle_t);
535ce0e08e2SPeter Avalos res.alock.fh.n_bytes = (char*)&fl->filehandle;
536ce0e08e2SPeter Avalos res.alock.oh = fl->client.oh;
537ce0e08e2SPeter Avalos res.alock.svid = fl->client.svid;
538ce0e08e2SPeter Avalos res.alock.l_offset = fl->client.l_offset;
539ce0e08e2SPeter Avalos res.alock.l_len = fl->client.l_len;
540ce0e08e2SPeter Avalos syslog(LOG_DEBUG, "sending v4 reply%s",
541ce0e08e2SPeter Avalos (fl->flags & LOCK_ASYNC) ? " (async)":"");
542ce0e08e2SPeter Avalos if (fl->flags & LOCK_ASYNC) {
543ce0e08e2SPeter Avalos success = clnt_call(cli, NLM4_GRANTED_MSG,
54473c42091SSascha Wildner (xdrproc_t)xdr_nlm4_testargs, &res,
54573c42091SSascha Wildner (xdrproc_t)xdr_void, &dummy, timeo);
546ce0e08e2SPeter Avalos } else {
547ce0e08e2SPeter Avalos success = clnt_call(cli, NLM4_GRANTED,
54873c42091SSascha Wildner (xdrproc_t)xdr_nlm4_testargs, &res,
54973c42091SSascha Wildner (xdrproc_t)xdr_nlm4_res, &retval4, timeo);
550ce0e08e2SPeter Avalos }
551ce0e08e2SPeter Avalos } else {
552ce0e08e2SPeter Avalos static nlm_testargs res;
553ce0e08e2SPeter Avalos
554ce0e08e2SPeter Avalos res.cookie = fl->client_cookie;
555ce0e08e2SPeter Avalos res.exclusive = fl->client.exclusive;
556ce0e08e2SPeter Avalos res.alock.caller_name = fl->client_name;
557ce0e08e2SPeter Avalos res.alock.fh.n_len = sizeof(fhandle_t);
558ce0e08e2SPeter Avalos res.alock.fh.n_bytes = (char*)&fl->filehandle;
559ce0e08e2SPeter Avalos res.alock.oh = fl->client.oh;
560ce0e08e2SPeter Avalos res.alock.svid = fl->client.svid;
561ce0e08e2SPeter Avalos res.alock.l_offset = fl->client.l_offset;
562ce0e08e2SPeter Avalos res.alock.l_len = fl->client.l_len;
563ce0e08e2SPeter Avalos syslog(LOG_DEBUG, "sending v1 reply%s",
564ce0e08e2SPeter Avalos (fl->flags & LOCK_ASYNC) ? " (async)":"");
565ce0e08e2SPeter Avalos if (fl->flags & LOCK_ASYNC) {
566ce0e08e2SPeter Avalos success = clnt_call(cli, NLM_GRANTED_MSG,
56773c42091SSascha Wildner (xdrproc_t)xdr_nlm_testargs, &res,
56873c42091SSascha Wildner (xdrproc_t)xdr_void, &dummy, timeo);
569ce0e08e2SPeter Avalos } else {
570ce0e08e2SPeter Avalos success = clnt_call(cli, NLM_GRANTED,
57173c42091SSascha Wildner (xdrproc_t)xdr_nlm_testargs, &res,
57273c42091SSascha Wildner (xdrproc_t)xdr_nlm_res, &retval, timeo);
573ce0e08e2SPeter Avalos }
574ce0e08e2SPeter Avalos }
575ce0e08e2SPeter Avalos if (debug_level > 2)
576ce0e08e2SPeter Avalos syslog(LOG_DEBUG, "clnt_call returns %d(%s) for granted",
577ce0e08e2SPeter Avalos success, clnt_sperrno(success));
578ce0e08e2SPeter Avalos
579ce0e08e2SPeter Avalos }
580ce0e08e2SPeter Avalos
581ce0e08e2SPeter Avalos enum nlm_stats
do_unlock(struct file_lock * rfl)582ce0e08e2SPeter Avalos do_unlock(struct file_lock *rfl)
583ce0e08e2SPeter Avalos {
584ce0e08e2SPeter Avalos struct file_lock *fl;
585ce0e08e2SPeter Avalos int error;
586ce0e08e2SPeter Avalos int lockst;
587ce0e08e2SPeter Avalos
588*29357d57SSascha Wildner /* unlock the file: closing is enough! */
589ce0e08e2SPeter Avalos if (close(rfl->fd) < 0) {
590ce0e08e2SPeter Avalos if (errno == ESTALE)
591ce0e08e2SPeter Avalos error = nlm4_stale_fh;
592ce0e08e2SPeter Avalos else
593ce0e08e2SPeter Avalos error = nlm4_failed;
594*29357d57SSascha Wildner if ((rfl->flags & LOCK_V4) == 0)
595ce0e08e2SPeter Avalos error = nlm_denied;
596ce0e08e2SPeter Avalos syslog(LOG_NOTICE,
597ce0e08e2SPeter Avalos "close failed (from %s): %s",
598ce0e08e2SPeter Avalos rfl->client_name, strerror(errno));
599ce0e08e2SPeter Avalos } else {
600*29357d57SSascha Wildner error = (rfl->flags & LOCK_V4) ?
601ce0e08e2SPeter Avalos nlm4_granted : nlm_granted;
602ce0e08e2SPeter Avalos }
603ce0e08e2SPeter Avalos LIST_REMOVE(rfl, lcklst);
604ce0e08e2SPeter Avalos
605ce0e08e2SPeter Avalos /* process the next LKST_WAITING lock request for this fh */
606ce0e08e2SPeter Avalos for (fl = LIST_FIRST(&lcklst_head); fl != NULL;
607ce0e08e2SPeter Avalos fl = LIST_NEXT(fl, lcklst)) {
608ce0e08e2SPeter Avalos if (fl->status != LKST_WAITING ||
609ce0e08e2SPeter Avalos memcmp(&rfl->filehandle, &fl->filehandle,
610ce0e08e2SPeter Avalos sizeof(fhandle_t)) != 0)
611ce0e08e2SPeter Avalos continue;
612ce0e08e2SPeter Avalos
613ce0e08e2SPeter Avalos lockst = do_lock(fl, 1); /* If it's LKST_WAITING we can block */
614ce0e08e2SPeter Avalos switch (lockst) {
615ce0e08e2SPeter Avalos case nlm4_granted:
616ce0e08e2SPeter Avalos /* case nlm_granted: same as nlm4_granted */
617ce0e08e2SPeter Avalos send_granted(fl, (fl->flags & LOCK_V4) ?
618ce0e08e2SPeter Avalos nlm4_granted : nlm_granted);
619ce0e08e2SPeter Avalos break;
620ce0e08e2SPeter Avalos case nlm4_blocked:
621ce0e08e2SPeter Avalos /* case nlm_blocked: same as nlm4_blocked */
622ce0e08e2SPeter Avalos break;
623ce0e08e2SPeter Avalos default:
624ce0e08e2SPeter Avalos lfree(fl);
625ce0e08e2SPeter Avalos break;
626ce0e08e2SPeter Avalos }
627ce0e08e2SPeter Avalos break;
628ce0e08e2SPeter Avalos }
629ce0e08e2SPeter Avalos return error;
630ce0e08e2SPeter Avalos }
631ce0e08e2SPeter Avalos
632ce0e08e2SPeter Avalos void
siglock(void)633ce0e08e2SPeter Avalos siglock(void)
634ce0e08e2SPeter Avalos {
635ce0e08e2SPeter Avalos sigset_t block;
636ce0e08e2SPeter Avalos
637ce0e08e2SPeter Avalos sigemptyset(&block);
638ce0e08e2SPeter Avalos sigaddset(&block, SIGCHLD);
639ce0e08e2SPeter Avalos
640ce0e08e2SPeter Avalos if (sigprocmask(SIG_BLOCK, &block, NULL) < 0) {
641ce0e08e2SPeter Avalos syslog(LOG_WARNING, "siglock failed: %s", strerror(errno));
642ce0e08e2SPeter Avalos }
643ce0e08e2SPeter Avalos }
644ce0e08e2SPeter Avalos
645ce0e08e2SPeter Avalos void
sigunlock(void)646ce0e08e2SPeter Avalos sigunlock(void)
647ce0e08e2SPeter Avalos {
648ce0e08e2SPeter Avalos sigset_t block;
649ce0e08e2SPeter Avalos
650ce0e08e2SPeter Avalos sigemptyset(&block);
651ce0e08e2SPeter Avalos sigaddset(&block, SIGCHLD);
652ce0e08e2SPeter Avalos
653ce0e08e2SPeter Avalos if (sigprocmask(SIG_UNBLOCK, &block, NULL) < 0) {
654ce0e08e2SPeter Avalos syslog(LOG_WARNING, "sigunlock failed: %s", strerror(errno));
655ce0e08e2SPeter Avalos }
656ce0e08e2SPeter Avalos }
657ce0e08e2SPeter Avalos
658ce0e08e2SPeter Avalos /* monitor a host through rpc.statd, and keep a ref count */
659ce0e08e2SPeter Avalos void
do_mon(char * hostname)660ce0e08e2SPeter Avalos do_mon(char *hostname)
661ce0e08e2SPeter Avalos {
662ce0e08e2SPeter Avalos struct host *hp;
663ce0e08e2SPeter Avalos struct mon my_mon;
664ce0e08e2SPeter Avalos struct sm_stat_res res;
665ce0e08e2SPeter Avalos int retval;
666ce0e08e2SPeter Avalos
667ce0e08e2SPeter Avalos for (hp = LIST_FIRST(&hostlst_head); hp != NULL;
668ce0e08e2SPeter Avalos hp = LIST_NEXT(hp, hostlst)) {
669ce0e08e2SPeter Avalos if (strcmp(hostname, hp->name) == 0) {
670ce0e08e2SPeter Avalos /* already monitored, just bump refcnt */
671ce0e08e2SPeter Avalos hp->refcnt++;
672ce0e08e2SPeter Avalos return;
673ce0e08e2SPeter Avalos }
674ce0e08e2SPeter Avalos }
675ce0e08e2SPeter Avalos /* not found, have to create an entry for it */
676ce0e08e2SPeter Avalos hp = malloc(sizeof(struct host));
677ce0e08e2SPeter Avalos strncpy(hp->name, hostname, SM_MAXSTRLEN);
678ce0e08e2SPeter Avalos hp->refcnt = 1;
679ce0e08e2SPeter Avalos syslog(LOG_DEBUG, "monitoring host %s",
680ce0e08e2SPeter Avalos hostname);
681ce0e08e2SPeter Avalos memset(&my_mon, 0, sizeof(my_mon));
682ce0e08e2SPeter Avalos my_mon.mon_id.mon_name = hp->name;
683ce0e08e2SPeter Avalos my_mon.mon_id.my_id.my_name = "localhost";
684ce0e08e2SPeter Avalos my_mon.mon_id.my_id.my_prog = NLM_PROG;
685ce0e08e2SPeter Avalos my_mon.mon_id.my_id.my_vers = NLM_SM;
686ce0e08e2SPeter Avalos my_mon.mon_id.my_id.my_proc = NLM_SM_NOTIFY;
687ce0e08e2SPeter Avalos if ((retval =
68873c42091SSascha Wildner callrpc("localhost", SM_PROG, SM_VERS, SM_MON, (xdrproc_t)xdr_mon,
68973c42091SSascha Wildner (char*)&my_mon, (xdrproc_t)xdr_sm_stat_res, (char*)&res)) != 0) {
690ce0e08e2SPeter Avalos syslog(LOG_WARNING, "rpc to statd failed: %s",
691ce0e08e2SPeter Avalos clnt_sperrno((enum clnt_stat)retval));
692ce0e08e2SPeter Avalos free(hp);
693ce0e08e2SPeter Avalos return;
694ce0e08e2SPeter Avalos }
695ce0e08e2SPeter Avalos if (res.res_stat == stat_fail) {
696ce0e08e2SPeter Avalos syslog(LOG_WARNING, "statd failed");
697ce0e08e2SPeter Avalos free(hp);
698ce0e08e2SPeter Avalos return;
699ce0e08e2SPeter Avalos }
700ce0e08e2SPeter Avalos LIST_INSERT_HEAD(&hostlst_head, hp, hostlst);
701ce0e08e2SPeter Avalos }
702ce0e08e2SPeter Avalos
703ce0e08e2SPeter Avalos void
notify(const char * hostname,int state)704ce0e08e2SPeter Avalos notify(const char *hostname, int state)
705ce0e08e2SPeter Avalos {
706ce0e08e2SPeter Avalos struct file_lock *fl, *next_fl;
707ce0e08e2SPeter Avalos int err;
708ce0e08e2SPeter Avalos syslog(LOG_DEBUG, "notify from %s, new state %d", hostname, state);
709ce0e08e2SPeter Avalos /* search all lock for this host; if status changed, release the lock */
710ce0e08e2SPeter Avalos siglock();
711ce0e08e2SPeter Avalos for (fl = LIST_FIRST(&lcklst_head); fl != NULL; fl = next_fl) {
712ce0e08e2SPeter Avalos next_fl = LIST_NEXT(fl, lcklst);
713ce0e08e2SPeter Avalos if (strcmp(hostname, fl->client_name) == 0 &&
714ce0e08e2SPeter Avalos fl->nsm_status != state) {
715ce0e08e2SPeter Avalos syslog(LOG_DEBUG, "state %d, nsm_state %d, unlocking",
716ce0e08e2SPeter Avalos fl->status, fl->nsm_status);
717ce0e08e2SPeter Avalos switch(fl->status) {
718ce0e08e2SPeter Avalos case LKST_LOCKED:
719ce0e08e2SPeter Avalos err = do_unlock(fl);
720ce0e08e2SPeter Avalos if (err != nlm_granted)
721ce0e08e2SPeter Avalos syslog(LOG_DEBUG,
722ce0e08e2SPeter Avalos "notify: unlock failed for %s (%d)",
723ce0e08e2SPeter Avalos hostname, err);
724ce0e08e2SPeter Avalos break;
725ce0e08e2SPeter Avalos case LKST_WAITING:
726ce0e08e2SPeter Avalos LIST_REMOVE(fl, lcklst);
727ce0e08e2SPeter Avalos lfree(fl);
728ce0e08e2SPeter Avalos break;
729ce0e08e2SPeter Avalos case LKST_PROCESSING:
730ce0e08e2SPeter Avalos fl->status = LKST_DYING;
731ce0e08e2SPeter Avalos break;
732ce0e08e2SPeter Avalos case LKST_DYING:
733ce0e08e2SPeter Avalos break;
734ce0e08e2SPeter Avalos default:
735ce0e08e2SPeter Avalos syslog(LOG_NOTICE, "unknown status %d for %s",
736ce0e08e2SPeter Avalos fl->status, fl->client_name);
737ce0e08e2SPeter Avalos }
738ce0e08e2SPeter Avalos }
739ce0e08e2SPeter Avalos }
740ce0e08e2SPeter Avalos sigunlock();
741ce0e08e2SPeter Avalos }
742