]> git.proxmox.com Git - pve-cluster.git/blame - data/src/cfs-plug-memdb.c
bump version to 7.3-2
[pve-cluster.git] / data / src / cfs-plug-memdb.c
CommitLineData
fe000966 1/*
84c98315 2 Copyright (C) 2010 - 2020 Proxmox Server Solutions GmbH
fe000966
DM
3
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Affero General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Affero General Public License for more details.
13
14 You should have received a copy of the GNU Affero General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17 Author: Dietmar Maurer <dietmar@proxmox.com>
18
19*/
20
21#ifdef HAVE_CONFIG_H
22#include <config.h>
23#endif /* HAVE_CONFIG_H */
24
25#include <stdlib.h>
26#include <stdio.h>
27#include <string.h>
28#include <unistd.h>
29#include <glib.h>
30#include <sys/types.h>
31#include <sys/stat.h>
32#include <sys/file.h>
33#include <fcntl.h>
34#include <errno.h>
35#include <dirent.h>
36#include <arpa/inet.h>
37
38#include "cfs-utils.h"
39#include "cfs-plug-memdb.h"
40#include "dcdb.h"
41#include "status.h"
42
43static struct cfs_operations cfs_ops;
44
c63b596f 45// FIXME: remove openvz stuff for 7.x
fd754ca1
DM
46static gboolean
47name_is_openvz_script(
48 const char *name,
49 guint32 *vmid_ret)
50{
51 if (!name)
52 return FALSE;
53
54 guint32 vmid = 0;
55 char *end = NULL;
56
57 if (name[0] == 'v' && name[1] == 'p' && name[2] == 's') {
58 end = (char *)name + 3;
59 } else {
60 if (name[0] < '1' || name[0] > '9')
61 return FALSE;
62
63 vmid = strtoul(name, &end, 10);
64 }
65
66 if (!end || end[0] != '.')
67 return FALSE;
68
69 end++;
70
71 gboolean res = FALSE;
72
73 if (end[0] == 'm' && strcmp(end, "mount") == 0)
74 res = TRUE;
75
76 if (end[0] == 'u' && strcmp(end, "umount") == 0)
77 res = TRUE;
78
79 if (end[0] == 's' &&
80 (strcmp(end, "start") == 0 || strcmp(end, "stop") == 0))
81 res = TRUE;
82
83 if (end[0] == 'p' &&
84 (strcmp(end, "premount") == 0 || strcmp(end, "postumount") == 0))
85 res = TRUE;
86
87
88 if (res && vmid_ret)
89 *vmid_ret = vmid;
90
91 return res;
92}
93
fe000966
DM
94static void tree_entry_stat(memdb_tree_entry_t *te, struct stat *stbuf, gboolean quorate)
95{
96 g_return_if_fail(te != NULL);
97 g_return_if_fail(stbuf != NULL);
98
99 if (te->type == DT_DIR) {
100 stbuf->st_mode = S_IFDIR | (quorate ? 0777 : 0555);
101 stbuf->st_nlink = 2;
102 } else {
103 stbuf->st_mode = S_IFREG | (quorate ? 0666 : 0444);
104 stbuf->st_nlink = 1;
c63b596f 105 // FIXME: remove openvz stuff for 7.x
fd754ca1
DM
106 if (name_is_openvz_script(te->name, NULL)) {
107 stbuf->st_mode |= S_IXUSR;
108 }
fe000966
DM
109 }
110
111 stbuf->st_size = te->size;
112 stbuf->st_blocks =
113 (stbuf->st_size + MEMDB_BLOCKSIZE -1)/MEMDB_BLOCKSIZE;
114 stbuf->st_atime = te->mtime;
115 stbuf->st_mtime = te->mtime;
116 stbuf->st_ctime = te->mtime;
117}
118
119static int cfs_plug_memdb_getattr(cfs_plug_t *plug, const char *path, struct stat *stbuf)
120{
121 g_return_val_if_fail(plug != NULL, PARAM_CHECK_ERRNO);
122 g_return_val_if_fail(plug->ops == &cfs_ops, PARAM_CHECK_ERRNO);
123 g_return_val_if_fail(path != NULL, PARAM_CHECK_ERRNO);
124 g_return_val_if_fail(stbuf != NULL, PARAM_CHECK_ERRNO);
125
126 memset(stbuf, 0, sizeof(struct stat));
127
128 cfs_plug_memdb_t *mdb = (cfs_plug_memdb_t *)plug;
129
130 memdb_tree_entry_t *te = memdb_getattr(mdb->memdb, path);
131
132 if (te) {
133 tree_entry_stat(te, stbuf, cfs_is_quorate());
a0fce192 134 memdb_tree_entry_free(te);
fe000966
DM
135 return 0;
136 }
137
138 return -ENOENT;
139}
140
141static int cfs_plug_memdb_readdir(
142 cfs_plug_t *plug,
143 const char *path,
144 void *buf,
145 fuse_fill_dir_t filler,
146 off_t offset,
147 struct fuse_file_info *fi)
148{
149 (void) offset;
150 (void) fi;
151
152 g_return_val_if_fail(plug != NULL, PARAM_CHECK_ERRNO);
153 g_return_val_if_fail(plug->ops == &cfs_ops, PARAM_CHECK_ERRNO);
154 g_return_val_if_fail(path != NULL, PARAM_CHECK_ERRNO);
155 g_return_val_if_fail(buf != NULL, PARAM_CHECK_ERRNO);
156 g_return_val_if_fail(filler != NULL, PARAM_CHECK_ERRNO);
157
158 cfs_plug_memdb_t *mdb = (cfs_plug_memdb_t *)plug;
159
160 GList *dirlist = memdb_readdir(mdb->memdb, path);
161
162 if (dirlist) {
163
164 filler(buf, ".", NULL, 0);
165 filler(buf, "..", NULL, 0);
166
167 struct stat stbuf;
168 memset(&stbuf, 0, sizeof(struct stat));
169
170 GList *l = dirlist;
171 while (l) {
172 memdb_tree_entry_t *te = (memdb_tree_entry_t *)l->data;
173
174 tree_entry_stat(te, &stbuf, 0);
175 filler(buf, te->name, &stbuf, 0);
176 l = g_list_next(l);
177 }
178
179 memdb_dirlist_free(dirlist);
180 }
181
182 return 0;
183}
184
185static int cfs_plug_memdb_open(cfs_plug_t *plug, const char *path, struct fuse_file_info *fi)
186{
187 g_return_val_if_fail(plug != NULL, PARAM_CHECK_ERRNO);
188 g_return_val_if_fail(plug->ops == &cfs_ops, PARAM_CHECK_ERRNO);
189 g_return_val_if_fail(path != NULL, PARAM_CHECK_ERRNO);
190 g_return_val_if_fail(fi != NULL, PARAM_CHECK_ERRNO);
191
192 memdb_tree_entry_t *te;
193
194 cfs_plug_memdb_t *mdb = (cfs_plug_memdb_t *)plug;
195
196 if ((te = memdb_getattr(mdb->memdb, path))) {
a0fce192 197 memdb_tree_entry_free(te);
fe000966
DM
198 } else
199 return -ENOENT;
200
201 return 0;
202}
203
204static int cfs_plug_memdb_read(
205 cfs_plug_t *plug,
206 const char *path,
207 char *buf,
208 size_t size,
209 off_t offset,
210 struct fuse_file_info *fi)
211{
212 (void) fi;
213
214 g_return_val_if_fail(plug != NULL, PARAM_CHECK_ERRNO);
215 g_return_val_if_fail(plug->ops == &cfs_ops, PARAM_CHECK_ERRNO);
216 g_return_val_if_fail(path != NULL, PARAM_CHECK_ERRNO);
217 g_return_val_if_fail(buf != NULL, PARAM_CHECK_ERRNO);
218
219 int len;
220 gpointer data = NULL;
221
222 cfs_plug_memdb_t *mdb = (cfs_plug_memdb_t *)plug;
223
224 len = memdb_read(mdb->memdb, path, &data);
225 if (len < 0)
226 return len;
227
228 if (offset < len) {
229 if (offset + size > len)
230 size = len - offset;
975f9b0c 231 memcpy(buf, (uint8_t *) data + offset, size);
fe000966
DM
232 } else {
233 size = 0;
234 }
235
236 if (data)
237 g_free(data);
238
239 return size;
240}
241
242static int cfs_plug_memdb_write(
243 cfs_plug_t *plug,
244 const char *path,
245 const char *buf,
246 size_t size,
247 off_t offset,
248 struct fuse_file_info *fi)
249{
250 (void) fi;
251
252 g_return_val_if_fail(plug != NULL, PARAM_CHECK_ERRNO);
253 g_return_val_if_fail(plug->ops == &cfs_ops, PARAM_CHECK_ERRNO);
254 g_return_val_if_fail(path != NULL, PARAM_CHECK_ERRNO);
255 g_return_val_if_fail(buf != NULL, PARAM_CHECK_ERRNO);
256
257 int res;
258
259 cfs_plug_memdb_t *mdb = (cfs_plug_memdb_t *)plug;
260
261 if (mdb->dfsm) {
262 res = dcdb_send_fuse_message(mdb->dfsm, DCDB_MESSAGE_CFS_WRITE, path, NULL, buf,
263 size, offset, 0);
264 } else {
265 uint32_t ctime = time(NULL);
266 res = memdb_write(mdb->memdb, path, 0, ctime, buf, size, offset, 0);
267 }
268
269 return res;
270}
271
272static int cfs_plug_memdb_truncate(cfs_plug_t *plug, const char *path, off_t size)
273{
274 g_return_val_if_fail(plug != NULL, PARAM_CHECK_ERRNO);
275 g_return_val_if_fail(plug->ops == &cfs_ops, PARAM_CHECK_ERRNO);
276 g_return_val_if_fail(path != NULL, PARAM_CHECK_ERRNO);
277
278 int res;
279
280 cfs_plug_memdb_t *mdb = (cfs_plug_memdb_t *)plug;
281
282 if (mdb->dfsm) {
283 res = dcdb_send_fuse_message(mdb->dfsm, DCDB_MESSAGE_CFS_WRITE, path, NULL, NULL,
284 0, size, 1);
285 } else {
286 uint32_t ctime = time(NULL);
287 res = memdb_write(mdb->memdb, path, 0, ctime, NULL, 0, size, 1);
288 }
289
290 return res;
291}
292
293static int cfs_plug_memdb_create (
294 cfs_plug_t *plug,
295 const char *path,
296 mode_t mode,
297 struct fuse_file_info *fi)
298{
299 g_return_val_if_fail(plug != NULL, PARAM_CHECK_ERRNO);
300 g_return_val_if_fail(plug->ops == &cfs_ops, PARAM_CHECK_ERRNO);
301 g_return_val_if_fail(path != NULL, PARAM_CHECK_ERRNO);
302 g_return_val_if_fail(fi != NULL, PARAM_CHECK_ERRNO);
303
304 int res;
305
306 cfs_plug_memdb_t *mdb = (cfs_plug_memdb_t *)plug;
307
308 if (mdb->dfsm) {
309 res = dcdb_send_fuse_message(mdb->dfsm, DCDB_MESSAGE_CFS_CREATE, path,
310 NULL, NULL, 0, 0, 0);
311 } else {
312 uint32_t ctime = time(NULL);
313
314 res = memdb_create(mdb->memdb, path, 0, ctime);
315 }
316
317 return res;
318}
319
320static int cfs_plug_memdb_mkdir(cfs_plug_t *plug, const char *path, mode_t mode)
321{
322 g_return_val_if_fail(plug != NULL, PARAM_CHECK_ERRNO);
323 g_return_val_if_fail(plug->ops == &cfs_ops, PARAM_CHECK_ERRNO);
324 g_return_val_if_fail(path != NULL, PARAM_CHECK_ERRNO);
325
326 int res;
327
328 cfs_plug_memdb_t *mdb = (cfs_plug_memdb_t *)plug;
329
330 if (mdb->dfsm) {
331 res = dcdb_send_fuse_message(mdb->dfsm, DCDB_MESSAGE_CFS_MKDIR, path,
332 NULL, NULL, 0, 0, 0);
333 } else {
334 uint32_t ctime = time(NULL);
335 res = memdb_mkdir(mdb->memdb, path, 0, ctime);
336 }
337
338 return res;
339}
340
341static int cfs_plug_memdb_rmdir(cfs_plug_t *plug, const char *path)
342{
343 g_return_val_if_fail(plug != NULL, PARAM_CHECK_ERRNO);
344 g_return_val_if_fail(plug->ops == &cfs_ops, PARAM_CHECK_ERRNO);
345 g_return_val_if_fail(path != NULL, PARAM_CHECK_ERRNO);
346
347 int res;
348
349 cfs_plug_memdb_t *mdb = (cfs_plug_memdb_t *)plug;
350
351 if (mdb->dfsm) {
352 res = dcdb_send_fuse_message(mdb->dfsm, DCDB_MESSAGE_CFS_DELETE, path,
353 NULL, NULL, 0, 0, 0);
354 } else {
355 uint32_t ctime = time(NULL);
356 res = memdb_delete(mdb->memdb, path, 0, ctime);
357 }
358
359 return res;
360}
361
362static int cfs_plug_memdb_rename(cfs_plug_t *plug, const char *from, const char *to)
363{
364 g_return_val_if_fail(plug != NULL, PARAM_CHECK_ERRNO);
365 g_return_val_if_fail(plug->ops == &cfs_ops, PARAM_CHECK_ERRNO);
366 g_return_val_if_fail(from != NULL, PARAM_CHECK_ERRNO);
367 g_return_val_if_fail(to != NULL, PARAM_CHECK_ERRNO);
368
369 int res;
370
371 cfs_plug_memdb_t *mdb = (cfs_plug_memdb_t *)plug;
372
373 if (mdb->dfsm) {
374 res = dcdb_send_fuse_message(mdb->dfsm, DCDB_MESSAGE_CFS_RENAME, from, to,
375 NULL, 0, 0, 0);
376 } else {
377 uint32_t ctime = time(NULL);
378 res = memdb_rename(mdb->memdb, from, to, 0, ctime);
379 }
380
381 return res;
382}
383
384static int cfs_plug_memdb_unlink(cfs_plug_t *plug, const char *path)
385{
386 g_return_val_if_fail(plug != NULL, PARAM_CHECK_ERRNO);
387 g_return_val_if_fail(plug->ops == &cfs_ops, PARAM_CHECK_ERRNO);
388 g_return_val_if_fail(path != NULL, PARAM_CHECK_ERRNO);
389
390 int res;
391
392 cfs_plug_memdb_t *mdb = (cfs_plug_memdb_t *)plug;
393
394 if (mdb->dfsm) {
395 res = dcdb_send_fuse_message(mdb->dfsm, DCDB_MESSAGE_CFS_DELETE, path,
396 NULL, NULL, 0, 0, 0);
397 } else {
398 uint32_t ctime = time(NULL);
399 res = memdb_delete(mdb->memdb, path, 0, ctime);
400 }
401
402 return res;
403}
404
405static int cfs_plug_memdb_utimens(
406 cfs_plug_t *plug,
407 const char *path,
408 const struct timespec tv[2])
409{
410 g_return_val_if_fail(plug != NULL, PARAM_CHECK_ERRNO);
411 g_return_val_if_fail(plug->ops == &cfs_ops, PARAM_CHECK_ERRNO);
412 g_return_val_if_fail(path != NULL, PARAM_CHECK_ERRNO);
413 g_return_val_if_fail(tv != NULL, PARAM_CHECK_ERRNO);
414
415 int res;
416
417 cfs_plug_memdb_t *mdb = (cfs_plug_memdb_t *)plug;
418
419 res = -EIO;
420
421 memdb_tree_entry_t *te = memdb_getattr(mdb->memdb, path);
422 uint32_t mtime = tv[1].tv_sec;
423
424 gboolean unlock_req = FALSE;
425 guchar csum[32];
426
427 if (te && mtime == 0 && te->type == DT_DIR &&
428 path_is_lockdir(path)) {
429 unlock_req = TRUE;
430 }
431
432 if (mdb->dfsm) {
433 if (unlock_req && memdb_tree_entry_csum(te, csum))
434 dcdb_send_unlock(mdb->dfsm, path, csum, TRUE);
435
436 res = dcdb_send_fuse_message(mdb->dfsm, DCDB_MESSAGE_CFS_MTIME, path,
437 NULL, NULL, 0, mtime, 0);
438 } else {
439 uint32_t ctime = time(NULL);
440 if (unlock_req && memdb_tree_entry_csum(te, csum) &&
441 memdb_lock_expired(mdb->memdb, path, csum)) {
442 res = memdb_delete(mdb->memdb, path, 0, ctime);
443 } else {
444 res = memdb_mtime(mdb->memdb, path, 0, mtime);
445 }
446 }
447
a0fce192 448 memdb_tree_entry_free(te);
fe000966
DM
449
450 return res;
451}
452
453static int cfs_plug_memdb_statfs(cfs_plug_t *plug, const char *path, struct statvfs *stbuf)
454{
455 g_return_val_if_fail(plug != NULL, PARAM_CHECK_ERRNO);
456 g_return_val_if_fail(plug->ops == &cfs_ops, PARAM_CHECK_ERRNO);
457 g_return_val_if_fail(path != NULL, PARAM_CHECK_ERRNO);
458 g_return_val_if_fail(stbuf != NULL, PARAM_CHECK_ERRNO);
459
460 cfs_plug_memdb_t *mdb = (cfs_plug_memdb_t *)plug;
461
462 return memdb_statfs(mdb->memdb, stbuf);
463}
464
465static void cfs_plug_memdb_destroy(cfs_plug_t *plug)
466{
467 g_return_if_fail(plug != NULL);
468 g_return_if_fail(plug->ops == &cfs_ops);
469
470 g_free(plug->name);
471
472 g_free(plug);
473}
474
475static cfs_plug_t *cfs_plug_memdb_lookup_plug(cfs_plug_t *plug, char **path)
476{
477 g_return_val_if_fail(plug != NULL, NULL);
478 g_return_val_if_fail(plug->ops == &cfs_ops, NULL);
479
480 return plug;
481}
482
483static struct cfs_operations cfs_ops = {
484 .getattr = cfs_plug_memdb_getattr,
485 .readdir = cfs_plug_memdb_readdir,
486 .open = cfs_plug_memdb_open,
487 .create = cfs_plug_memdb_create,
488 .read = cfs_plug_memdb_read,
489 .write = cfs_plug_memdb_write,
490 .truncate = cfs_plug_memdb_truncate,
491 .unlink = cfs_plug_memdb_unlink,
492 .mkdir = cfs_plug_memdb_mkdir,
493 .rmdir = cfs_plug_memdb_rmdir,
494 .rename = cfs_plug_memdb_rename,
495 .utimens = cfs_plug_memdb_utimens,
496 .statfs = cfs_plug_memdb_statfs,
497#ifdef HAS_CFS_PLUG_MEMDB_LOCK
498 .lock = cfs_plug_memdb_lock,
499#endif
500};
501
502cfs_plug_memdb_t *cfs_plug_memdb_new(
503 const char *name,
504 memdb_t *memdb,
505 dfsm_t *dfsm)
506{
507 g_return_val_if_fail(name != NULL, NULL);
508 g_return_val_if_fail(memdb != NULL, NULL);
509
510 cfs_plug_memdb_t *mdb = g_new0(cfs_plug_memdb_t, 1);
511
512 g_return_val_if_fail(mdb != NULL, NULL);
513
514 mdb->plug.ops = &cfs_ops;
515
516 mdb->plug.lookup_plug = cfs_plug_memdb_lookup_plug;
517
518 mdb->plug.destroy_plug = cfs_plug_memdb_destroy;
519
520 mdb->plug.name = g_strdup(name);
521
522 mdb->memdb = memdb;
523
524 mdb->dfsm = dfsm;
525
526 return mdb;
527}