GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/rpc.lockd/lockd_lock.c Lines: 0 364 0.0 %
Date: 2017-11-07 Branches: 0 192 0.0 %

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