Imported Upstream version 2.02.79
[platform/upstream/device-mapper.git] / daemons / clvmd / clvmd-singlenode.c
1 /*
2  * Copyright (C) 2009 Red Hat, Inc. All rights reserved.
3  *
4  * This file is part of LVM2.
5  *
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.
9  *
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
13  */
14
15 #include "clvmd-common.h"
16
17 #include <pthread.h>
18
19 #include "locking.h"
20 #include "clvm.h"
21 #include "clvmd-comms.h"
22 #include "lvm-functions.h"
23 #include "clvmd.h"
24
25 #include <sys/un.h>
26 #include <sys/socket.h>
27 #include <fcntl.h>
28
29 static const char SINGLENODE_CLVMD_SOCKNAME[] = DEFAULT_RUN_DIR "/clvmd_singlenode.sock";
30 static int listen_fd = -1;
31
32 static void close_comms(void)
33 {
34         if (listen_fd != -1 && close(listen_fd))
35                 stack;
36         (void)unlink(SINGLENODE_CLVMD_SOCKNAME);
37         listen_fd = -1;
38 }
39
40 static int init_comms(void)
41 {
42         struct sockaddr_un addr;
43         mode_t old_mask;
44
45         close_comms();
46
47         (void) dm_prepare_selinux_context(SINGLENODE_CLVMD_SOCKNAME, S_IFSOCK);
48         old_mask = umask(0077);
49
50         listen_fd = socket(PF_UNIX, SOCK_STREAM, 0);
51         if (listen_fd < 0) {
52                 DEBUGLOG("Can't create local socket: %s\n", strerror(errno));
53                 goto error;
54         }
55         /* Set Close-on-exec */
56         fcntl(listen_fd, F_SETFD, 1);
57
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;
62
63         if (bind(listen_fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
64                 DEBUGLOG("Can't bind local socket: %s\n", strerror(errno));
65                 goto error;
66         }
67         if (listen(listen_fd, 10) < 0) {
68                 DEBUGLOG("Can't listen local socket: %s\n", strerror(errno));
69                 goto error;
70         }
71
72         umask(old_mask);
73         (void) dm_prepare_selinux_context(NULL, 0);
74         return 0;
75 error:
76         umask(old_mask);
77         (void) dm_prepare_selinux_context(NULL, 0);
78         close_comms();
79         return -1;
80 }
81
82 static int _init_cluster(void)
83 {
84         int r;
85
86         r = init_comms();
87         if (r)
88                 return r;
89
90         DEBUGLOG("Single-node cluster initialised.\n");
91         return 0;
92 }
93
94 static void _cluster_closedown(void)
95 {
96         close_comms();
97
98         DEBUGLOG("cluster_closedown\n");
99         destroy_lvhash();
100 }
101
102 static void _get_our_csid(char *csid)
103 {
104         int nodeid = 1;
105         memcpy(csid, &nodeid, sizeof(int));
106 }
107
108 static int _csid_from_name(char *csid, const char *name)
109 {
110         return 1;
111 }
112
113 static int _name_from_csid(const char *csid, char *name)
114 {
115         sprintf(name, "SINGLENODE");
116         return 0;
117 }
118
119 static int _get_num_nodes(void)
120 {
121         return 1;
122 }
123
124 /* Node is now known to be running a clvmd */
125 static void _add_up_node(const char *csid)
126 {
127 }
128
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))
133 {
134         return 0;
135 }
136
137 int _lock_file(const char *file, uint32_t flags);
138
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;
143
144 /* Real locking */
145 static int _lock_resource(const char *resource, int mode, int flags, int *lockid)
146 {
147         int *_locks_1;
148         char **_resources_1;
149         int i, j;
150
151         DEBUGLOG("lock_resource '%s', flags=%d, mode=%d\n",
152                  resource, flags, mode);
153
154  retry:
155         pthread_mutex_lock(&_lock_mutex);
156
157         /* look for an existing lock for this resource */
158         for (i = 1; i < _lock_max; ++i) {
159                 if (!_resources[i])
160                         break;
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);
165                                 goto maybe_retry;
166                         }
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",
170                                          resource);
171                                 goto maybe_retry;
172                         }
173                 }
174         }
175
176         if (i == _lock_max) { /* out of lock slots, extend */
177                 _locks_1 = dm_realloc(_locks, 2 * _lock_max * sizeof(int));
178                 if (!_locks_1)
179                         return 1; /* fail */
180                 _locks = _locks_1;
181                 _resources_1 = dm_realloc(_resources, 2 * _lock_max * sizeof(char *));
182                 if (!_resources_1) {
183                         /* _locks may get realloc'd twice, but that should be safe */
184                         return 1; /* fail */
185                 }
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;
191         }
192
193         /* resource is not currently locked, grab it */
194
195         *lockid = i;
196         _locks[i] = mode;
197         _resources[i] = dm_strdup(resource);
198
199         DEBUGLOG("%s locked -> %d\n", resource, i);
200
201         pthread_mutex_unlock(&_lock_mutex);
202         return 0;
203  maybe_retry:
204         pthread_mutex_unlock(&_lock_mutex);
205         if (!(flags & LCK_NONBLOCK)) {
206                 usleep(10000);
207                 goto retry;
208         }
209
210         return 1; /* fail */
211 }
212
213 static int _unlock_resource(const char *resource, int lockid)
214 {
215         DEBUGLOG("unlock_resource: %s lockid: %x\n", resource, lockid);
216         if(!_resources[lockid]) {
217                 DEBUGLOG("(%s) %d not locked\n", resource, lockid);
218                 return 1;
219         }
220         if(strcmp(_resources[lockid], resource)) {
221                 DEBUGLOG("%d has wrong resource (requested %s, got %s)\n",
222                          lockid, resource, _resources[lockid]);
223                 return 1;
224         }
225
226         dm_free(_resources[lockid]);
227         _resources[lockid] = 0;
228         return 0;
229 }
230
231 static int _is_quorate(void)
232 {
233         return 1;
234 }
235
236 static int _get_main_cluster_fd(void)
237 {
238         return listen_fd;
239 }
240
241 static int _cluster_fd_callback(struct local_client *fd, char *buf, int len,
242                                 const char *csid,
243                                 struct local_client **new_client)
244 {
245         return 1;
246 }
247
248 static int _cluster_send_message(const void *buf, int msglen,
249                                  const char *csid,
250                                  const char *errtext)
251 {
252         return 0;
253 }
254
255 static int _get_cluster_name(char *buf, int buflen)
256 {
257         strncpy(buf, "localcluster", buflen);
258         buf[buflen - 1] = 0;
259         return 0;
260 }
261
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,
279 };
280
281 struct cluster_ops *init_singlenode_cluster(void)
282 {
283         if (!_init_cluster())
284                 return &_cluster_singlenode_ops;
285         else
286                 return NULL;
287 }