2 * Copyright (C) 2009 Red Hat, Inc. All rights reserved.
4 * This file is part of LVM2.
6 * This copyrighted material is made available to anyone wishing to use,
7 * modify, copy, or redistribute it subject to the terms and conditions
8 * of the GNU Lesser General Public License v.2.1.
10 * You should have received a copy of the GNU Lesser General Public License
11 * along with this program; if not, write to the Free Software Foundation,
12 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15 #include "clvmd-common.h"
21 #include "clvmd-comms.h"
22 #include "lvm-functions.h"
26 #include <sys/socket.h>
29 static const char SINGLENODE_CLVMD_SOCKNAME[] = DEFAULT_RUN_DIR "/clvmd_singlenode.sock";
30 static int listen_fd = -1;
32 static void close_comms(void)
34 if (listen_fd != -1 && close(listen_fd))
36 (void)unlink(SINGLENODE_CLVMD_SOCKNAME);
40 static int init_comms(void)
42 struct sockaddr_un addr;
47 (void) dm_prepare_selinux_context(SINGLENODE_CLVMD_SOCKNAME, S_IFSOCK);
48 old_mask = umask(0077);
50 listen_fd = socket(PF_UNIX, SOCK_STREAM, 0);
52 DEBUGLOG("Can't create local socket: %s\n", strerror(errno));
55 /* Set Close-on-exec */
56 fcntl(listen_fd, F_SETFD, 1);
58 memset(&addr, 0, sizeof(addr));
59 memcpy(addr.sun_path, SINGLENODE_CLVMD_SOCKNAME,
60 sizeof(SINGLENODE_CLVMD_SOCKNAME));
61 addr.sun_family = AF_UNIX;
63 if (bind(listen_fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
64 DEBUGLOG("Can't bind local socket: %s\n", strerror(errno));
67 if (listen(listen_fd, 10) < 0) {
68 DEBUGLOG("Can't listen local socket: %s\n", strerror(errno));
73 (void) dm_prepare_selinux_context(NULL, 0);
77 (void) dm_prepare_selinux_context(NULL, 0);
82 static int _init_cluster(void)
90 DEBUGLOG("Single-node cluster initialised.\n");
94 static void _cluster_closedown(void)
98 DEBUGLOG("cluster_closedown\n");
102 static void _get_our_csid(char *csid)
105 memcpy(csid, &nodeid, sizeof(int));
108 static int _csid_from_name(char *csid, const char *name)
113 static int _name_from_csid(const char *csid, char *name)
115 sprintf(name, "SINGLENODE");
119 static int _get_num_nodes(void)
124 /* Node is now known to be running a clvmd */
125 static void _add_up_node(const char *csid)
129 /* Call a callback for each node, so the caller knows whether it's up or down */
130 static int _cluster_do_node_callback(struct local_client *master_client,
131 void (*callback)(struct local_client *,
132 const char *csid, int node_up))
137 int _lock_file(const char *file, uint32_t flags);
139 static int *_locks = NULL;
140 static char **_resources = NULL;
141 static int _lock_max = 1;
142 static pthread_mutex_t _lock_mutex = PTHREAD_MUTEX_INITIALIZER;
145 static int _lock_resource(const char *resource, int mode, int flags, int *lockid)
151 DEBUGLOG("lock_resource '%s', flags=%d, mode=%d\n",
152 resource, flags, mode);
155 pthread_mutex_lock(&_lock_mutex);
157 /* look for an existing lock for this resource */
158 for (i = 1; i < _lock_max; ++i) {
161 if (!strcmp(_resources[i], resource)) {
162 if ((_locks[i] & LCK_TYPE_MASK) == LCK_WRITE ||
163 (_locks[i] & LCK_TYPE_MASK) == LCK_EXCL) {
164 DEBUGLOG("%s already write/exclusively locked...\n", resource);
167 if ((mode & LCK_TYPE_MASK) == LCK_WRITE ||
168 (mode & LCK_TYPE_MASK) == LCK_EXCL) {
169 DEBUGLOG("%s already locked and WRITE/EXCL lock requested...\n",
176 if (i == _lock_max) { /* out of lock slots, extend */
177 _locks_1 = dm_realloc(_locks, 2 * _lock_max * sizeof(int));
181 _resources_1 = dm_realloc(_resources, 2 * _lock_max * sizeof(char *));
183 /* _locks may get realloc'd twice, but that should be safe */
186 _resources = _resources_1;
187 /* clear the new resource entries */
188 for (j = _lock_max; j < 2 * _lock_max; ++j)
189 _resources[j] = NULL;
190 _lock_max = 2 * _lock_max;
193 /* resource is not currently locked, grab it */
197 _resources[i] = dm_strdup(resource);
199 DEBUGLOG("%s locked -> %d\n", resource, i);
201 pthread_mutex_unlock(&_lock_mutex);
204 pthread_mutex_unlock(&_lock_mutex);
205 if (!(flags & LCK_NONBLOCK)) {
213 static int _unlock_resource(const char *resource, int lockid)
215 DEBUGLOG("unlock_resource: %s lockid: %x\n", resource, lockid);
216 if(!_resources[lockid]) {
217 DEBUGLOG("(%s) %d not locked\n", resource, lockid);
220 if(strcmp(_resources[lockid], resource)) {
221 DEBUGLOG("%d has wrong resource (requested %s, got %s)\n",
222 lockid, resource, _resources[lockid]);
226 dm_free(_resources[lockid]);
227 _resources[lockid] = 0;
231 static int _is_quorate(void)
236 static int _get_main_cluster_fd(void)
241 static int _cluster_fd_callback(struct local_client *fd, char *buf, int len,
243 struct local_client **new_client)
248 static int _cluster_send_message(const void *buf, int msglen,
255 static int _get_cluster_name(char *buf, int buflen)
257 strncpy(buf, "localcluster", buflen);
262 static struct cluster_ops _cluster_singlenode_ops = {
263 .cluster_init_completed = NULL,
264 .cluster_send_message = _cluster_send_message,
265 .name_from_csid = _name_from_csid,
266 .csid_from_name = _csid_from_name,
267 .get_num_nodes = _get_num_nodes,
268 .cluster_fd_callback = _cluster_fd_callback,
269 .get_main_cluster_fd = _get_main_cluster_fd,
270 .cluster_do_node_callback = _cluster_do_node_callback,
271 .is_quorate = _is_quorate,
272 .get_our_csid = _get_our_csid,
273 .add_up_node = _add_up_node,
274 .reread_config = NULL,
275 .cluster_closedown = _cluster_closedown,
276 .get_cluster_name = _get_cluster_name,
277 .sync_lock = _lock_resource,
278 .sync_unlock = _unlock_resource,
281 struct cluster_ops *init_singlenode_cluster(void)
283 if (!_init_cluster())
284 return &_cluster_singlenode_ops;