]> git.proxmox.com Git - pve-cluster.git/blame - data/src/cfs-plug-func.c
cfs-func-plug: use RW lock for safe cached data access
[pve-cluster.git] / data / src / cfs-plug-func.c
CommitLineData
fe000966
DM
1/*
2 Copyright (C) 2011 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
37#include "cfs-utils.h"
38#include "cfs-plug.h"
39
40static struct cfs_operations cfs_ops;
41
42static cfs_plug_t *cfs_plug_func_lookup_plug(cfs_plug_t *plug, char **path)
43{
44 g_return_val_if_fail(plug != NULL, NULL);
45 g_return_val_if_fail(plug->ops == &cfs_ops, NULL);
46
47 return (!*path || !(*path)[0]) ? plug : NULL;
48}
49
50static void cfs_plug_func_destroy(cfs_plug_t *plug)
51{
52 g_return_if_fail(plug != NULL);
53 g_return_if_fail(plug->ops == &cfs_ops);
54
55 cfs_plug_func_t *fplug = (cfs_plug_func_t *)plug;
56
57 cfs_debug("enter cfs_plug_func_destroy %s", plug->name);
58
59 if (fplug->data)
60 g_free(fplug->data);
61
62 g_free(plug->name);
63
64 g_free(plug);
65}
66
67static int
68cfs_plug_func_getattr(
69 cfs_plug_t *plug,
70 const char *path,
71 struct stat *stbuf)
72{
73 g_return_val_if_fail(plug != NULL, PARAM_CHECK_ERRNO);
74 g_return_val_if_fail(plug->ops == &cfs_ops, PARAM_CHECK_ERRNO);
75 g_return_val_if_fail(path != NULL, PARAM_CHECK_ERRNO);
76 g_return_val_if_fail(stbuf != NULL, PARAM_CHECK_ERRNO);
77
78 cfs_debug("enter cfs_plug_func_getattr %s", path);
79
80 cfs_plug_func_t *fplug = (cfs_plug_func_t *)plug;
81
82 memset(stbuf, 0, sizeof(struct stat));
83
77b98e81 84 g_rw_lock_writer_lock(&fplug->data_rw_lock);
fe000966
DM
85 if (fplug->data)
86 g_free(fplug->data);
87
88 fplug->data = fplug->update_callback(plug);
89
77b98e81
TL
90 stbuf->st_size = fplug->data ? strlen(fplug->data) : 0;
91
92 g_rw_lock_writer_unlock(&fplug->data_rw_lock);
93
fe000966
DM
94 stbuf->st_mode = fplug->mode;
95 stbuf->st_nlink = 1;
fe000966
DM
96
97 return 0;
98}
99
100static int
101cfs_plug_func_read(
102 cfs_plug_t *plug,
103 const char *path,
104 char *buf,
105 size_t size,
106 off_t offset,
107 struct fuse_file_info *fi)
108{
109 (void) fi;
110
111 g_return_val_if_fail(plug != NULL, PARAM_CHECK_ERRNO);
112 g_return_val_if_fail(plug->ops == &cfs_ops, PARAM_CHECK_ERRNO);
113 g_return_val_if_fail(path != NULL, PARAM_CHECK_ERRNO);
114 g_return_val_if_fail(buf != NULL, PARAM_CHECK_ERRNO);
115
116 cfs_plug_func_t *fplug = (cfs_plug_func_t *)plug;
117
77b98e81 118 g_rw_lock_reader_lock(&fplug->data_rw_lock);
fe000966
DM
119 char *data = fplug->data;
120
121 cfs_debug("enter cfs_plug_func_read %s", data);
122
77b98e81
TL
123 if (!data) {
124 g_rw_lock_reader_unlock(&fplug->data_rw_lock);
fe000966 125 return 0;
77b98e81 126 }
fe000966
DM
127
128 int len = strlen(data);
129
130 if (offset < len) {
131 if (offset + size > len)
132 size = len - offset;
133 memcpy(buf, data + offset, size);
134 } else {
135 size = 0;
136 }
77b98e81 137 g_rw_lock_reader_unlock(&fplug->data_rw_lock);
fe000966
DM
138
139 return size;
140}
141
142static int
143cfs_plug_func_write(
144 cfs_plug_t *plug,
145 const char *path,
146 const char *buf,
147 size_t size,
148 off_t offset,
149 struct fuse_file_info *fi)
150{
151 (void) fi;
152
153 g_return_val_if_fail(plug != NULL, PARAM_CHECK_ERRNO);
154 g_return_val_if_fail(plug->ops == &cfs_ops, PARAM_CHECK_ERRNO);
155 g_return_val_if_fail(path != NULL, PARAM_CHECK_ERRNO);
156 g_return_val_if_fail(buf != NULL, PARAM_CHECK_ERRNO);
157
158 cfs_debug("enter cfs_plug_func_write");
159
160 cfs_plug_func_t *fplug = (cfs_plug_func_t *)plug;
161
162 if (offset != 0 || !fplug->write_callback)
163 return -EIO;
164
165 return fplug->write_callback(plug, buf, size);
166}
167
168static int
169cfs_plug_func_truncate(
170 cfs_plug_t *plug,
171 const char *path,
172 off_t size)
173{
174 g_return_val_if_fail(plug != NULL, PARAM_CHECK_ERRNO);
175 g_return_val_if_fail(plug->ops == &cfs_ops, PARAM_CHECK_ERRNO);
176 g_return_val_if_fail(path != NULL, PARAM_CHECK_ERRNO);
177
178 cfs_plug_func_t *fplug = (cfs_plug_func_t *)plug;
179
180 if (fplug->write_callback)
181 return 0;
182
183 return -EIO;
184}
185
186static int
187cfs_plug_func_open(
188 cfs_plug_t *plug,
189 const char *path,
190 struct fuse_file_info *fi)
191{
192 g_return_val_if_fail(plug != NULL, PARAM_CHECK_ERRNO);
193 g_return_val_if_fail(plug->ops == &cfs_ops, PARAM_CHECK_ERRNO);
194 g_return_val_if_fail(path != NULL, PARAM_CHECK_ERRNO);
195 g_return_val_if_fail(fi != NULL, PARAM_CHECK_ERRNO);
196
197 cfs_debug("enter cfs_plug_func_open %s", path);
198
199 return 0;
200}
201
202static struct cfs_operations cfs_ops = {
203 .getattr = cfs_plug_func_getattr,
204 .read = cfs_plug_func_read,
205 .write = cfs_plug_func_write,
206 .truncate = cfs_plug_func_truncate,
207 .open = cfs_plug_func_open,
208};
209
210
211cfs_plug_func_t *
212cfs_plug_func_new(
213 const char *name,
214 mode_t mode,
215 cfs_plug_func_udpate_data_fn_t update_callback,
216 cfs_plug_func_write_data_fn_t write_callback)
217{
218 g_return_val_if_fail(name != NULL, NULL);
219 g_return_val_if_fail(update_callback != NULL, NULL);
220
221 cfs_plug_func_t *fplug = g_new0(cfs_plug_func_t, 1);
222
223 fplug->plug.ops = &cfs_ops;
224
225 fplug->plug.lookup_plug = cfs_plug_func_lookup_plug;
226 fplug->plug.destroy_plug = cfs_plug_func_destroy;
227
228 fplug->plug.name = g_strdup(name);
229
230 fplug->update_callback = update_callback;
231 fplug->write_callback = write_callback;
232 if (!write_callback)
233 mode = mode & ~0222;
234
235 fplug->mode = S_IFREG | mode;
236
237 return fplug;
238}
239