2 Copyright (C) 2010 Proxmox Server Solutions GmbH
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.
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.
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/>.
17 Author: Dietmar Maurer <dietmar@proxmox.com>
23 #endif /* HAVE_CONFIG_H */
30 #include <sys/types.h>
36 #include <arpa/inet.h>
38 #include "cfs-utils.h"
39 #include "cfs-plug-memdb.h"
43 static struct cfs_operations cfs_ops
;
46 name_is_openvz_script(
56 if (name
[0] == 'v' && name
[1] == 'p' && name
[2] == 's') {
57 end
= (char *)name
+ 3;
59 if (name
[0] < '1' || name
[0] > '9')
62 vmid
= strtoul(name
, &end
, 10);
65 if (!end
|| end
[0] != '.')
72 if (end
[0] == 'm' && strcmp(end
, "mount") == 0)
75 if (end
[0] == 'u' && strcmp(end
, "umount") == 0)
79 (strcmp(end
, "start") == 0 || strcmp(end
, "stop") == 0))
83 (strcmp(end
, "premount") == 0 || strcmp(end
, "postumount") == 0))
93 static void tree_entry_stat(memdb_tree_entry_t
*te
, struct stat
*stbuf
, gboolean quorate
)
95 g_return_if_fail(te
!= NULL
);
96 g_return_if_fail(stbuf
!= NULL
);
98 if (te
->type
== DT_DIR
) {
99 stbuf
->st_mode
= S_IFDIR
| (quorate
? 0777 : 0555);
102 stbuf
->st_mode
= S_IFREG
| (quorate
? 0666 : 0444);
104 if (name_is_openvz_script(te
->name
, NULL
)) {
105 stbuf
->st_mode
|= S_IXUSR
;
109 stbuf
->st_size
= te
->size
;
111 (stbuf
->st_size
+ MEMDB_BLOCKSIZE
-1)/MEMDB_BLOCKSIZE
;
112 stbuf
->st_atime
= te
->mtime
;
113 stbuf
->st_mtime
= te
->mtime
;
114 stbuf
->st_ctime
= te
->mtime
;
117 static int cfs_plug_memdb_getattr(cfs_plug_t
*plug
, const char *path
, struct stat
*stbuf
)
119 g_return_val_if_fail(plug
!= NULL
, PARAM_CHECK_ERRNO
);
120 g_return_val_if_fail(plug
->ops
== &cfs_ops
, PARAM_CHECK_ERRNO
);
121 g_return_val_if_fail(path
!= NULL
, PARAM_CHECK_ERRNO
);
122 g_return_val_if_fail(stbuf
!= NULL
, PARAM_CHECK_ERRNO
);
124 memset(stbuf
, 0, sizeof(struct stat
));
126 cfs_plug_memdb_t
*mdb
= (cfs_plug_memdb_t
*)plug
;
128 memdb_tree_entry_t
*te
= memdb_getattr(mdb
->memdb
, path
);
131 tree_entry_stat(te
, stbuf
, cfs_is_quorate());
132 memdb_tree_entry_free(te
);
139 static int cfs_plug_memdb_readdir(
143 fuse_fill_dir_t filler
,
145 struct fuse_file_info
*fi
)
150 g_return_val_if_fail(plug
!= NULL
, PARAM_CHECK_ERRNO
);
151 g_return_val_if_fail(plug
->ops
== &cfs_ops
, PARAM_CHECK_ERRNO
);
152 g_return_val_if_fail(path
!= NULL
, PARAM_CHECK_ERRNO
);
153 g_return_val_if_fail(buf
!= NULL
, PARAM_CHECK_ERRNO
);
154 g_return_val_if_fail(filler
!= NULL
, PARAM_CHECK_ERRNO
);
156 cfs_plug_memdb_t
*mdb
= (cfs_plug_memdb_t
*)plug
;
158 GList
*dirlist
= memdb_readdir(mdb
->memdb
, path
);
162 filler(buf
, ".", NULL
, 0);
163 filler(buf
, "..", NULL
, 0);
166 memset(&stbuf
, 0, sizeof(struct stat
));
170 memdb_tree_entry_t
*te
= (memdb_tree_entry_t
*)l
->data
;
172 tree_entry_stat(te
, &stbuf
, 0);
173 filler(buf
, te
->name
, &stbuf
, 0);
177 memdb_dirlist_free(dirlist
);
183 static int cfs_plug_memdb_open(cfs_plug_t
*plug
, const char *path
, struct fuse_file_info
*fi
)
185 g_return_val_if_fail(plug
!= NULL
, PARAM_CHECK_ERRNO
);
186 g_return_val_if_fail(plug
->ops
== &cfs_ops
, PARAM_CHECK_ERRNO
);
187 g_return_val_if_fail(path
!= NULL
, PARAM_CHECK_ERRNO
);
188 g_return_val_if_fail(fi
!= NULL
, PARAM_CHECK_ERRNO
);
190 memdb_tree_entry_t
*te
;
192 cfs_plug_memdb_t
*mdb
= (cfs_plug_memdb_t
*)plug
;
194 if ((te
= memdb_getattr(mdb
->memdb
, path
))) {
195 memdb_tree_entry_free(te
);
202 static int cfs_plug_memdb_read(
208 struct fuse_file_info
*fi
)
212 g_return_val_if_fail(plug
!= NULL
, PARAM_CHECK_ERRNO
);
213 g_return_val_if_fail(plug
->ops
== &cfs_ops
, PARAM_CHECK_ERRNO
);
214 g_return_val_if_fail(path
!= NULL
, PARAM_CHECK_ERRNO
);
215 g_return_val_if_fail(buf
!= NULL
, PARAM_CHECK_ERRNO
);
218 gpointer data
= NULL
;
220 cfs_plug_memdb_t
*mdb
= (cfs_plug_memdb_t
*)plug
;
222 len
= memdb_read(mdb
->memdb
, path
, &data
);
227 if (offset
+ size
> len
)
229 memcpy(buf
, data
+ offset
, size
);
240 static int cfs_plug_memdb_write(
246 struct fuse_file_info
*fi
)
250 g_return_val_if_fail(plug
!= NULL
, PARAM_CHECK_ERRNO
);
251 g_return_val_if_fail(plug
->ops
== &cfs_ops
, PARAM_CHECK_ERRNO
);
252 g_return_val_if_fail(path
!= NULL
, PARAM_CHECK_ERRNO
);
253 g_return_val_if_fail(buf
!= NULL
, PARAM_CHECK_ERRNO
);
257 cfs_plug_memdb_t
*mdb
= (cfs_plug_memdb_t
*)plug
;
260 res
= dcdb_send_fuse_message(mdb
->dfsm
, DCDB_MESSAGE_CFS_WRITE
, path
, NULL
, buf
,
263 uint32_t ctime
= time(NULL
);
264 res
= memdb_write(mdb
->memdb
, path
, 0, ctime
, buf
, size
, offset
, 0);
270 static int cfs_plug_memdb_truncate(cfs_plug_t
*plug
, const char *path
, off_t size
)
272 g_return_val_if_fail(plug
!= NULL
, PARAM_CHECK_ERRNO
);
273 g_return_val_if_fail(plug
->ops
== &cfs_ops
, PARAM_CHECK_ERRNO
);
274 g_return_val_if_fail(path
!= NULL
, PARAM_CHECK_ERRNO
);
278 cfs_plug_memdb_t
*mdb
= (cfs_plug_memdb_t
*)plug
;
281 res
= dcdb_send_fuse_message(mdb
->dfsm
, DCDB_MESSAGE_CFS_WRITE
, path
, NULL
, NULL
,
284 uint32_t ctime
= time(NULL
);
285 res
= memdb_write(mdb
->memdb
, path
, 0, ctime
, NULL
, 0, size
, 1);
291 static int cfs_plug_memdb_create (
295 struct fuse_file_info
*fi
)
297 g_return_val_if_fail(plug
!= NULL
, PARAM_CHECK_ERRNO
);
298 g_return_val_if_fail(plug
->ops
== &cfs_ops
, PARAM_CHECK_ERRNO
);
299 g_return_val_if_fail(path
!= NULL
, PARAM_CHECK_ERRNO
);
300 g_return_val_if_fail(fi
!= NULL
, PARAM_CHECK_ERRNO
);
304 cfs_plug_memdb_t
*mdb
= (cfs_plug_memdb_t
*)plug
;
307 res
= dcdb_send_fuse_message(mdb
->dfsm
, DCDB_MESSAGE_CFS_CREATE
, path
,
308 NULL
, NULL
, 0, 0, 0);
310 uint32_t ctime
= time(NULL
);
312 res
= memdb_create(mdb
->memdb
, path
, 0, ctime
);
318 static int cfs_plug_memdb_mkdir(cfs_plug_t
*plug
, const char *path
, mode_t mode
)
320 g_return_val_if_fail(plug
!= NULL
, PARAM_CHECK_ERRNO
);
321 g_return_val_if_fail(plug
->ops
== &cfs_ops
, PARAM_CHECK_ERRNO
);
322 g_return_val_if_fail(path
!= NULL
, PARAM_CHECK_ERRNO
);
326 cfs_plug_memdb_t
*mdb
= (cfs_plug_memdb_t
*)plug
;
329 res
= dcdb_send_fuse_message(mdb
->dfsm
, DCDB_MESSAGE_CFS_MKDIR
, path
,
330 NULL
, NULL
, 0, 0, 0);
332 uint32_t ctime
= time(NULL
);
333 res
= memdb_mkdir(mdb
->memdb
, path
, 0, ctime
);
339 static int cfs_plug_memdb_rmdir(cfs_plug_t
*plug
, const char *path
)
341 g_return_val_if_fail(plug
!= NULL
, PARAM_CHECK_ERRNO
);
342 g_return_val_if_fail(plug
->ops
== &cfs_ops
, PARAM_CHECK_ERRNO
);
343 g_return_val_if_fail(path
!= NULL
, PARAM_CHECK_ERRNO
);
347 cfs_plug_memdb_t
*mdb
= (cfs_plug_memdb_t
*)plug
;
350 res
= dcdb_send_fuse_message(mdb
->dfsm
, DCDB_MESSAGE_CFS_DELETE
, path
,
351 NULL
, NULL
, 0, 0, 0);
353 uint32_t ctime
= time(NULL
);
354 res
= memdb_delete(mdb
->memdb
, path
, 0, ctime
);
360 static int cfs_plug_memdb_rename(cfs_plug_t
*plug
, const char *from
, const char *to
)
362 g_return_val_if_fail(plug
!= NULL
, PARAM_CHECK_ERRNO
);
363 g_return_val_if_fail(plug
->ops
== &cfs_ops
, PARAM_CHECK_ERRNO
);
364 g_return_val_if_fail(from
!= NULL
, PARAM_CHECK_ERRNO
);
365 g_return_val_if_fail(to
!= NULL
, PARAM_CHECK_ERRNO
);
369 cfs_plug_memdb_t
*mdb
= (cfs_plug_memdb_t
*)plug
;
372 res
= dcdb_send_fuse_message(mdb
->dfsm
, DCDB_MESSAGE_CFS_RENAME
, from
, to
,
375 uint32_t ctime
= time(NULL
);
376 res
= memdb_rename(mdb
->memdb
, from
, to
, 0, ctime
);
382 static int cfs_plug_memdb_unlink(cfs_plug_t
*plug
, const char *path
)
384 g_return_val_if_fail(plug
!= NULL
, PARAM_CHECK_ERRNO
);
385 g_return_val_if_fail(plug
->ops
== &cfs_ops
, PARAM_CHECK_ERRNO
);
386 g_return_val_if_fail(path
!= NULL
, PARAM_CHECK_ERRNO
);
390 cfs_plug_memdb_t
*mdb
= (cfs_plug_memdb_t
*)plug
;
393 res
= dcdb_send_fuse_message(mdb
->dfsm
, DCDB_MESSAGE_CFS_DELETE
, path
,
394 NULL
, NULL
, 0, 0, 0);
396 uint32_t ctime
= time(NULL
);
397 res
= memdb_delete(mdb
->memdb
, path
, 0, ctime
);
403 static int cfs_plug_memdb_utimens(
406 const struct timespec tv
[2])
408 g_return_val_if_fail(plug
!= NULL
, PARAM_CHECK_ERRNO
);
409 g_return_val_if_fail(plug
->ops
== &cfs_ops
, PARAM_CHECK_ERRNO
);
410 g_return_val_if_fail(path
!= NULL
, PARAM_CHECK_ERRNO
);
411 g_return_val_if_fail(tv
!= NULL
, PARAM_CHECK_ERRNO
);
415 cfs_plug_memdb_t
*mdb
= (cfs_plug_memdb_t
*)plug
;
419 memdb_tree_entry_t
*te
= memdb_getattr(mdb
->memdb
, path
);
420 uint32_t mtime
= tv
[1].tv_sec
;
422 gboolean unlock_req
= FALSE
;
425 if (te
&& mtime
== 0 && te
->type
== DT_DIR
&&
426 path_is_lockdir(path
)) {
431 if (unlock_req
&& memdb_tree_entry_csum(te
, csum
))
432 dcdb_send_unlock(mdb
->dfsm
, path
, csum
, TRUE
);
434 res
= dcdb_send_fuse_message(mdb
->dfsm
, DCDB_MESSAGE_CFS_MTIME
, path
,
435 NULL
, NULL
, 0, mtime
, 0);
437 uint32_t ctime
= time(NULL
);
438 if (unlock_req
&& memdb_tree_entry_csum(te
, csum
) &&
439 memdb_lock_expired(mdb
->memdb
, path
, csum
)) {
440 res
= memdb_delete(mdb
->memdb
, path
, 0, ctime
);
442 res
= memdb_mtime(mdb
->memdb
, path
, 0, mtime
);
446 memdb_tree_entry_free(te
);
451 static int cfs_plug_memdb_statfs(cfs_plug_t
*plug
, const char *path
, struct statvfs
*stbuf
)
453 g_return_val_if_fail(plug
!= NULL
, PARAM_CHECK_ERRNO
);
454 g_return_val_if_fail(plug
->ops
== &cfs_ops
, PARAM_CHECK_ERRNO
);
455 g_return_val_if_fail(path
!= NULL
, PARAM_CHECK_ERRNO
);
456 g_return_val_if_fail(stbuf
!= NULL
, PARAM_CHECK_ERRNO
);
458 cfs_plug_memdb_t
*mdb
= (cfs_plug_memdb_t
*)plug
;
460 return memdb_statfs(mdb
->memdb
, stbuf
);
463 static void cfs_plug_memdb_destroy(cfs_plug_t
*plug
)
465 g_return_if_fail(plug
!= NULL
);
466 g_return_if_fail(plug
->ops
== &cfs_ops
);
473 static cfs_plug_t
*cfs_plug_memdb_lookup_plug(cfs_plug_t
*plug
, char **path
)
475 g_return_val_if_fail(plug
!= NULL
, NULL
);
476 g_return_val_if_fail(plug
->ops
== &cfs_ops
, NULL
);
481 static struct cfs_operations cfs_ops
= {
482 .getattr
= cfs_plug_memdb_getattr
,
483 .readdir
= cfs_plug_memdb_readdir
,
484 .open
= cfs_plug_memdb_open
,
485 .create
= cfs_plug_memdb_create
,
486 .read
= cfs_plug_memdb_read
,
487 .write
= cfs_plug_memdb_write
,
488 .truncate
= cfs_plug_memdb_truncate
,
489 .unlink
= cfs_plug_memdb_unlink
,
490 .mkdir
= cfs_plug_memdb_mkdir
,
491 .rmdir
= cfs_plug_memdb_rmdir
,
492 .rename
= cfs_plug_memdb_rename
,
493 .utimens
= cfs_plug_memdb_utimens
,
494 .statfs
= cfs_plug_memdb_statfs
,
495 #ifdef HAS_CFS_PLUG_MEMDB_LOCK
496 .lock
= cfs_plug_memdb_lock
,
500 cfs_plug_memdb_t
*cfs_plug_memdb_new(
505 g_return_val_if_fail(name
!= NULL
, NULL
);
506 g_return_val_if_fail(memdb
!= NULL
, NULL
);
508 cfs_plug_memdb_t
*mdb
= g_new0(cfs_plug_memdb_t
, 1);
510 g_return_val_if_fail(mdb
!= NULL
, NULL
);
512 mdb
->plug
.ops
= &cfs_ops
;
514 mdb
->plug
.lookup_plug
= cfs_plug_memdb_lookup_plug
;
516 mdb
->plug
.destroy_plug
= cfs_plug_memdb_destroy
;
518 mdb
->plug
.name
= g_strdup(name
);