]> git.proxmox.com Git - pve-cluster.git/blob - data/src/cfs-plug-memdb.c
77ec1c1cf412739422e7fe7a61c1c6bf953be5e5
[pve-cluster.git] / data / src / cfs-plug-memdb.c
1 /*
2 Copyright (C) 2010 Proxmox Server Solutions GmbH
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
43 static struct cfs_operations cfs_ops;
44
45 static void tree_entry_stat(memdb_tree_entry_t *te, struct stat *stbuf, gboolean quorate)
46 {
47 g_return_if_fail(te != NULL);
48 g_return_if_fail(stbuf != NULL);
49
50 if (te->type == DT_DIR) {
51 stbuf->st_mode = S_IFDIR | (quorate ? 0777 : 0555);
52 stbuf->st_nlink = 2;
53 } else {
54 stbuf->st_mode = S_IFREG | (quorate ? 0666 : 0444);
55 stbuf->st_nlink = 1;
56 }
57
58 stbuf->st_size = te->size;
59 stbuf->st_blocks =
60 (stbuf->st_size + MEMDB_BLOCKSIZE -1)/MEMDB_BLOCKSIZE;
61 stbuf->st_atime = te->mtime;
62 stbuf->st_mtime = te->mtime;
63 stbuf->st_ctime = te->mtime;
64 }
65
66 static int cfs_plug_memdb_getattr(cfs_plug_t *plug, const char *path, struct stat *stbuf)
67 {
68 g_return_val_if_fail(plug != NULL, PARAM_CHECK_ERRNO);
69 g_return_val_if_fail(plug->ops == &cfs_ops, PARAM_CHECK_ERRNO);
70 g_return_val_if_fail(path != NULL, PARAM_CHECK_ERRNO);
71 g_return_val_if_fail(stbuf != NULL, PARAM_CHECK_ERRNO);
72
73 memset(stbuf, 0, sizeof(struct stat));
74
75 cfs_plug_memdb_t *mdb = (cfs_plug_memdb_t *)plug;
76
77 memdb_tree_entry_t *te = memdb_getattr(mdb->memdb, path);
78
79 if (te) {
80 tree_entry_stat(te, stbuf, cfs_is_quorate());
81 g_free(te);
82 return 0;
83 }
84
85 return -ENOENT;
86 }
87
88 static int cfs_plug_memdb_readdir(
89 cfs_plug_t *plug,
90 const char *path,
91 void *buf,
92 fuse_fill_dir_t filler,
93 off_t offset,
94 struct fuse_file_info *fi)
95 {
96 (void) offset;
97 (void) fi;
98
99 g_return_val_if_fail(plug != NULL, PARAM_CHECK_ERRNO);
100 g_return_val_if_fail(plug->ops == &cfs_ops, PARAM_CHECK_ERRNO);
101 g_return_val_if_fail(path != NULL, PARAM_CHECK_ERRNO);
102 g_return_val_if_fail(buf != NULL, PARAM_CHECK_ERRNO);
103 g_return_val_if_fail(filler != NULL, PARAM_CHECK_ERRNO);
104
105 cfs_plug_memdb_t *mdb = (cfs_plug_memdb_t *)plug;
106
107 GList *dirlist = memdb_readdir(mdb->memdb, path);
108
109 if (dirlist) {
110
111 filler(buf, ".", NULL, 0);
112 filler(buf, "..", NULL, 0);
113
114 struct stat stbuf;
115 memset(&stbuf, 0, sizeof(struct stat));
116
117 GList *l = dirlist;
118 while (l) {
119 memdb_tree_entry_t *te = (memdb_tree_entry_t *)l->data;
120
121 tree_entry_stat(te, &stbuf, 0);
122 filler(buf, te->name, &stbuf, 0);
123 l = g_list_next(l);
124 }
125
126 memdb_dirlist_free(dirlist);
127 }
128
129 return 0;
130 }
131
132 static int cfs_plug_memdb_open(cfs_plug_t *plug, const char *path, struct fuse_file_info *fi)
133 {
134 g_return_val_if_fail(plug != NULL, PARAM_CHECK_ERRNO);
135 g_return_val_if_fail(plug->ops == &cfs_ops, PARAM_CHECK_ERRNO);
136 g_return_val_if_fail(path != NULL, PARAM_CHECK_ERRNO);
137 g_return_val_if_fail(fi != NULL, PARAM_CHECK_ERRNO);
138
139 memdb_tree_entry_t *te;
140
141 cfs_plug_memdb_t *mdb = (cfs_plug_memdb_t *)plug;
142
143 if ((te = memdb_getattr(mdb->memdb, path))) {
144 g_free(te);
145 } else
146 return -ENOENT;
147
148 return 0;
149 }
150
151 static int cfs_plug_memdb_read(
152 cfs_plug_t *plug,
153 const char *path,
154 char *buf,
155 size_t size,
156 off_t offset,
157 struct fuse_file_info *fi)
158 {
159 (void) fi;
160
161 g_return_val_if_fail(plug != NULL, PARAM_CHECK_ERRNO);
162 g_return_val_if_fail(plug->ops == &cfs_ops, PARAM_CHECK_ERRNO);
163 g_return_val_if_fail(path != NULL, PARAM_CHECK_ERRNO);
164 g_return_val_if_fail(buf != NULL, PARAM_CHECK_ERRNO);
165
166 int len;
167 gpointer data = NULL;
168
169 cfs_plug_memdb_t *mdb = (cfs_plug_memdb_t *)plug;
170
171 len = memdb_read(mdb->memdb, path, &data);
172 if (len < 0)
173 return len;
174
175 if (offset < len) {
176 if (offset + size > len)
177 size = len - offset;
178 memcpy(buf, data + offset, size);
179 } else {
180 size = 0;
181 }
182
183 if (data)
184 g_free(data);
185
186 return size;
187 }
188
189 static int cfs_plug_memdb_write(
190 cfs_plug_t *plug,
191 const char *path,
192 const char *buf,
193 size_t size,
194 off_t offset,
195 struct fuse_file_info *fi)
196 {
197 (void) fi;
198
199 g_return_val_if_fail(plug != NULL, PARAM_CHECK_ERRNO);
200 g_return_val_if_fail(plug->ops == &cfs_ops, PARAM_CHECK_ERRNO);
201 g_return_val_if_fail(path != NULL, PARAM_CHECK_ERRNO);
202 g_return_val_if_fail(buf != NULL, PARAM_CHECK_ERRNO);
203
204 int res;
205
206 cfs_plug_memdb_t *mdb = (cfs_plug_memdb_t *)plug;
207
208 if (mdb->dfsm) {
209 res = dcdb_send_fuse_message(mdb->dfsm, DCDB_MESSAGE_CFS_WRITE, path, NULL, buf,
210 size, offset, 0);
211 } else {
212 uint32_t ctime = time(NULL);
213 res = memdb_write(mdb->memdb, path, 0, ctime, buf, size, offset, 0);
214 }
215
216 return res;
217 }
218
219 static int cfs_plug_memdb_truncate(cfs_plug_t *plug, const char *path, off_t size)
220 {
221 g_return_val_if_fail(plug != NULL, PARAM_CHECK_ERRNO);
222 g_return_val_if_fail(plug->ops == &cfs_ops, PARAM_CHECK_ERRNO);
223 g_return_val_if_fail(path != NULL, PARAM_CHECK_ERRNO);
224
225 int res;
226
227 cfs_plug_memdb_t *mdb = (cfs_plug_memdb_t *)plug;
228
229 if (mdb->dfsm) {
230 res = dcdb_send_fuse_message(mdb->dfsm, DCDB_MESSAGE_CFS_WRITE, path, NULL, NULL,
231 0, size, 1);
232 } else {
233 uint32_t ctime = time(NULL);
234 res = memdb_write(mdb->memdb, path, 0, ctime, NULL, 0, size, 1);
235 }
236
237 return res;
238 }
239
240 static int cfs_plug_memdb_create (
241 cfs_plug_t *plug,
242 const char *path,
243 mode_t mode,
244 struct fuse_file_info *fi)
245 {
246 g_return_val_if_fail(plug != NULL, PARAM_CHECK_ERRNO);
247 g_return_val_if_fail(plug->ops == &cfs_ops, PARAM_CHECK_ERRNO);
248 g_return_val_if_fail(path != NULL, PARAM_CHECK_ERRNO);
249 g_return_val_if_fail(fi != NULL, PARAM_CHECK_ERRNO);
250
251 int res;
252
253 cfs_plug_memdb_t *mdb = (cfs_plug_memdb_t *)plug;
254
255 if (mdb->dfsm) {
256 res = dcdb_send_fuse_message(mdb->dfsm, DCDB_MESSAGE_CFS_CREATE, path,
257 NULL, NULL, 0, 0, 0);
258 } else {
259 uint32_t ctime = time(NULL);
260
261 res = memdb_create(mdb->memdb, path, 0, ctime);
262 }
263
264 return res;
265 }
266
267 static int cfs_plug_memdb_mkdir(cfs_plug_t *plug, const char *path, mode_t mode)
268 {
269 g_return_val_if_fail(plug != NULL, PARAM_CHECK_ERRNO);
270 g_return_val_if_fail(plug->ops == &cfs_ops, PARAM_CHECK_ERRNO);
271 g_return_val_if_fail(path != NULL, PARAM_CHECK_ERRNO);
272
273 int res;
274
275 cfs_plug_memdb_t *mdb = (cfs_plug_memdb_t *)plug;
276
277 if (mdb->dfsm) {
278 res = dcdb_send_fuse_message(mdb->dfsm, DCDB_MESSAGE_CFS_MKDIR, path,
279 NULL, NULL, 0, 0, 0);
280 } else {
281 uint32_t ctime = time(NULL);
282 res = memdb_mkdir(mdb->memdb, path, 0, ctime);
283 }
284
285 return res;
286 }
287
288 static int cfs_plug_memdb_rmdir(cfs_plug_t *plug, const char *path)
289 {
290 g_return_val_if_fail(plug != NULL, PARAM_CHECK_ERRNO);
291 g_return_val_if_fail(plug->ops == &cfs_ops, PARAM_CHECK_ERRNO);
292 g_return_val_if_fail(path != NULL, PARAM_CHECK_ERRNO);
293
294 int res;
295
296 cfs_plug_memdb_t *mdb = (cfs_plug_memdb_t *)plug;
297
298 if (mdb->dfsm) {
299 res = dcdb_send_fuse_message(mdb->dfsm, DCDB_MESSAGE_CFS_DELETE, path,
300 NULL, NULL, 0, 0, 0);
301 } else {
302 uint32_t ctime = time(NULL);
303 res = memdb_delete(mdb->memdb, path, 0, ctime);
304 }
305
306 return res;
307 }
308
309 static int cfs_plug_memdb_rename(cfs_plug_t *plug, const char *from, const char *to)
310 {
311 g_return_val_if_fail(plug != NULL, PARAM_CHECK_ERRNO);
312 g_return_val_if_fail(plug->ops == &cfs_ops, PARAM_CHECK_ERRNO);
313 g_return_val_if_fail(from != NULL, PARAM_CHECK_ERRNO);
314 g_return_val_if_fail(to != NULL, PARAM_CHECK_ERRNO);
315
316 int res;
317
318 cfs_plug_memdb_t *mdb = (cfs_plug_memdb_t *)plug;
319
320 if (mdb->dfsm) {
321 res = dcdb_send_fuse_message(mdb->dfsm, DCDB_MESSAGE_CFS_RENAME, from, to,
322 NULL, 0, 0, 0);
323 } else {
324 uint32_t ctime = time(NULL);
325 res = memdb_rename(mdb->memdb, from, to, 0, ctime);
326 }
327
328 return res;
329 }
330
331 static int cfs_plug_memdb_unlink(cfs_plug_t *plug, const char *path)
332 {
333 g_return_val_if_fail(plug != NULL, PARAM_CHECK_ERRNO);
334 g_return_val_if_fail(plug->ops == &cfs_ops, PARAM_CHECK_ERRNO);
335 g_return_val_if_fail(path != NULL, PARAM_CHECK_ERRNO);
336
337 int res;
338
339 cfs_plug_memdb_t *mdb = (cfs_plug_memdb_t *)plug;
340
341 if (mdb->dfsm) {
342 res = dcdb_send_fuse_message(mdb->dfsm, DCDB_MESSAGE_CFS_DELETE, path,
343 NULL, NULL, 0, 0, 0);
344 } else {
345 uint32_t ctime = time(NULL);
346 res = memdb_delete(mdb->memdb, path, 0, ctime);
347 }
348
349 return res;
350 }
351
352 static int cfs_plug_memdb_utimens(
353 cfs_plug_t *plug,
354 const char *path,
355 const struct timespec tv[2])
356 {
357 g_return_val_if_fail(plug != NULL, PARAM_CHECK_ERRNO);
358 g_return_val_if_fail(plug->ops == &cfs_ops, PARAM_CHECK_ERRNO);
359 g_return_val_if_fail(path != NULL, PARAM_CHECK_ERRNO);
360 g_return_val_if_fail(tv != NULL, PARAM_CHECK_ERRNO);
361
362 int res;
363
364 cfs_plug_memdb_t *mdb = (cfs_plug_memdb_t *)plug;
365
366 res = -EIO;
367
368 memdb_tree_entry_t *te = memdb_getattr(mdb->memdb, path);
369 uint32_t mtime = tv[1].tv_sec;
370
371 gboolean unlock_req = FALSE;
372 guchar csum[32];
373
374 if (te && mtime == 0 && te->type == DT_DIR &&
375 path_is_lockdir(path)) {
376 unlock_req = TRUE;
377 }
378
379 if (mdb->dfsm) {
380 if (unlock_req && memdb_tree_entry_csum(te, csum))
381 dcdb_send_unlock(mdb->dfsm, path, csum, TRUE);
382
383 res = dcdb_send_fuse_message(mdb->dfsm, DCDB_MESSAGE_CFS_MTIME, path,
384 NULL, NULL, 0, mtime, 0);
385 } else {
386 uint32_t ctime = time(NULL);
387 if (unlock_req && memdb_tree_entry_csum(te, csum) &&
388 memdb_lock_expired(mdb->memdb, path, csum)) {
389 res = memdb_delete(mdb->memdb, path, 0, ctime);
390 } else {
391 res = memdb_mtime(mdb->memdb, path, 0, mtime);
392 }
393 }
394
395 if (te)
396 g_free(te);
397
398 return res;
399 }
400
401 static int cfs_plug_memdb_statfs(cfs_plug_t *plug, const char *path, struct statvfs *stbuf)
402 {
403 g_return_val_if_fail(plug != NULL, PARAM_CHECK_ERRNO);
404 g_return_val_if_fail(plug->ops == &cfs_ops, PARAM_CHECK_ERRNO);
405 g_return_val_if_fail(path != NULL, PARAM_CHECK_ERRNO);
406 g_return_val_if_fail(stbuf != NULL, PARAM_CHECK_ERRNO);
407
408 cfs_plug_memdb_t *mdb = (cfs_plug_memdb_t *)plug;
409
410 return memdb_statfs(mdb->memdb, stbuf);
411 }
412
413 static void cfs_plug_memdb_destroy(cfs_plug_t *plug)
414 {
415 g_return_if_fail(plug != NULL);
416 g_return_if_fail(plug->ops == &cfs_ops);
417
418 g_free(plug->name);
419
420 g_free(plug);
421 }
422
423 static cfs_plug_t *cfs_plug_memdb_lookup_plug(cfs_plug_t *plug, char **path)
424 {
425 g_return_val_if_fail(plug != NULL, NULL);
426 g_return_val_if_fail(plug->ops == &cfs_ops, NULL);
427
428 return plug;
429 }
430
431 static struct cfs_operations cfs_ops = {
432 .getattr = cfs_plug_memdb_getattr,
433 .readdir = cfs_plug_memdb_readdir,
434 .open = cfs_plug_memdb_open,
435 .create = cfs_plug_memdb_create,
436 .read = cfs_plug_memdb_read,
437 .write = cfs_plug_memdb_write,
438 .truncate = cfs_plug_memdb_truncate,
439 .unlink = cfs_plug_memdb_unlink,
440 .mkdir = cfs_plug_memdb_mkdir,
441 .rmdir = cfs_plug_memdb_rmdir,
442 .rename = cfs_plug_memdb_rename,
443 .utimens = cfs_plug_memdb_utimens,
444 .statfs = cfs_plug_memdb_statfs,
445 #ifdef HAS_CFS_PLUG_MEMDB_LOCK
446 .lock = cfs_plug_memdb_lock,
447 #endif
448 };
449
450 cfs_plug_memdb_t *cfs_plug_memdb_new(
451 const char *name,
452 memdb_t *memdb,
453 dfsm_t *dfsm)
454 {
455 g_return_val_if_fail(name != NULL, NULL);
456 g_return_val_if_fail(memdb != NULL, NULL);
457
458 cfs_plug_memdb_t *mdb = g_new0(cfs_plug_memdb_t, 1);
459
460 g_return_val_if_fail(mdb != NULL, NULL);
461
462 mdb->plug.ops = &cfs_ops;
463
464 mdb->plug.lookup_plug = cfs_plug_memdb_lookup_plug;
465
466 mdb->plug.destroy_plug = cfs_plug_memdb_destroy;
467
468 mdb->plug.name = g_strdup(name);
469
470 mdb->memdb = memdb;
471
472 mdb->dfsm = dfsm;
473
474 return mdb;
475 }