rangelock.c revision 225787
1178476Sjb/*-
2178476Sjb * Copyright (c) 2010 The FreeBSD Foundation
3178476Sjb * All rights reserved.
4178476Sjb *
5178476Sjb * This software was developed by Pawel Jakub Dawidek under sponsorship from
6178476Sjb * the FreeBSD Foundation.
7178476Sjb *
8178476Sjb * Redistribution and use in source and binary forms, with or without
9178476Sjb * modification, are permitted provided that the following conditions
10178476Sjb * are met:
11178476Sjb * 1. Redistributions of source code must retain the above copyright
12178476Sjb *    notice, this list of conditions and the following disclaimer.
13178476Sjb * 2. Redistributions in binary form must reproduce the above copyright
14178476Sjb *    notice, this list of conditions and the following disclaimer in the
15178476Sjb *    documentation and/or other materials provided with the distribution.
16178476Sjb *
17178476Sjb * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
18178476Sjb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19178476Sjb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20178476Sjb * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
21178476Sjb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22178476Sjb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23178476Sjb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24178476Sjb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25267937Srpaulo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26178476Sjb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27178476Sjb * SUCH DAMAGE.
28178476Sjb */
29178476Sjb
30178476Sjb#include <sys/cdefs.h>
31178476Sjb__FBSDID("$FreeBSD: head/sbin/hastd/rangelock.c 225787 2011-09-27 08:50:37Z pjd $");
32178476Sjb
33178476Sjb#include <sys/queue.h>
34178476Sjb
35178476Sjb#include <stdbool.h>
36178476Sjb#include <stdlib.h>
37178476Sjb#include <unistd.h>
38178476Sjb
39178476Sjb#include <pjdlog.h>
40178476Sjb
41178476Sjb#include "rangelock.h"
42178476Sjb
43178476Sjb#ifndef	PJDLOG_ASSERT
44178476Sjb#include <assert.h>
45178476Sjb#define	PJDLOG_ASSERT(...)	assert(__VA_ARGS__)
46178476Sjb#endif
47178476Sjb
48178476Sjb#define	RANGELOCKS_MAGIC	0x94310c
49178476Sjbstruct rangelocks {
50178476Sjb	int	 rls_magic;		/* Magic value. */
51178476Sjb	TAILQ_HEAD(, rlock) rls_locks;	/* List of locked ranges. */
52178476Sjb};
53178476Sjb
54178476Sjbstruct rlock {
55178476Sjb	off_t	rl_start;
56178476Sjb	off_t	rl_end;
57178476Sjb	TAILQ_ENTRY(rlock) rl_next;
58178476Sjb};
59178476Sjb
60178476Sjbint
61178476Sjbrangelock_init(struct rangelocks **rlsp)
62178476Sjb{
63178476Sjb	struct rangelocks *rls;
64178476Sjb
65178476Sjb	PJDLOG_ASSERT(rlsp != NULL);
66178476Sjb
67178476Sjb	rls = malloc(sizeof(*rls));
68178476Sjb	if (rls == NULL)
69178476Sjb		return (-1);
70178476Sjb
71178476Sjb	TAILQ_INIT(&rls->rls_locks);
72178476Sjb
73178476Sjb	rls->rls_magic = RANGELOCKS_MAGIC;
74178476Sjb	*rlsp = rls;
75178476Sjb
76178476Sjb	return (0);
77178476Sjb}
78178476Sjb
79178476Sjbvoid
80178476Sjbrangelock_free(struct rangelocks *rls)
81178476Sjb{
82178476Sjb	struct rlock *rl;
83178476Sjb
84178476Sjb	PJDLOG_ASSERT(rls->rls_magic == RANGELOCKS_MAGIC);
85178476Sjb
86178476Sjb	rls->rls_magic = 0;
87178476Sjb
88178476Sjb	while ((rl = TAILQ_FIRST(&rls->rls_locks)) != NULL) {
89178476Sjb		TAILQ_REMOVE(&rls->rls_locks, rl, rl_next);
90178476Sjb		free(rl);
91178476Sjb	}
92178476Sjb	free(rls);
93178476Sjb}
94178476Sjb
95178476Sjbint
96178476Sjbrangelock_add(struct rangelocks *rls, off_t offset, off_t length)
97178476Sjb{
98178476Sjb	struct rlock *rl;
99178476Sjb
100178476Sjb	PJDLOG_ASSERT(rls->rls_magic == RANGELOCKS_MAGIC);
101267929Srpaulo
102267937Srpaulo	rl = malloc(sizeof(*rl));
103267937Srpaulo	if (rl == NULL)
104178476Sjb		return (-1);
105178476Sjb	rl->rl_start = offset;
106178476Sjb	rl->rl_end = offset + length;
107178476Sjb	TAILQ_INSERT_TAIL(&rls->rls_locks, rl, rl_next);
108178476Sjb	return (0);
109178476Sjb}
110178476Sjb
111178476Sjbvoid
112178476Sjbrangelock_del(struct rangelocks *rls, off_t offset, off_t length)
113178476Sjb{
114178476Sjb	struct rlock *rl;
115178476Sjb
116	PJDLOG_ASSERT(rls->rls_magic == RANGELOCKS_MAGIC);
117
118	TAILQ_FOREACH(rl, &rls->rls_locks, rl_next) {
119		if (rl->rl_start == offset && rl->rl_end == offset + length)
120			break;
121	}
122	PJDLOG_ASSERT(rl != NULL);
123	TAILQ_REMOVE(&rls->rls_locks, rl, rl_next);
124	free(rl);
125}
126
127bool
128rangelock_islocked(struct rangelocks *rls, off_t offset, off_t length)
129{
130	struct rlock *rl;
131
132	PJDLOG_ASSERT(rls->rls_magic == RANGELOCKS_MAGIC);
133
134	TAILQ_FOREACH(rl, &rls->rls_locks, rl_next) {
135		if (rl->rl_start >= offset && rl->rl_start < offset + length)
136			break;
137		else if (rl->rl_end > offset && rl->rl_end <= offset + length)
138			break;
139		else if (rl->rl_start < offset && rl->rl_end > offset + length)
140			break;
141	}
142	return (rl != NULL);
143}
144