selftest: export/use CTDB related envvars in order to run the ctdb command
[Samba.git] / source3 / modules / vfs_syncops.c
blob94dcd7b846eda3fb665010ea8855e528c3339fcb
1 /*
2 * ensure meta data operations are performed synchronously
4 * Copyright (C) Andrew Tridgell 2007
5 * Copyright (C) Christian Ambach, 2010-2011
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include "includes.h"
23 #include "system/filesys.h"
24 #include "smbd/smbd.h"
28 Some filesystems (even some journaled filesystems) require that a
29 fsync() be performed on many meta data operations to ensure that the
30 operation is guaranteed to remain in the filesystem after a power
31 failure. This is particularly important for some cluster filesystems
32 which are participating in a node failover system with clustered
33 Samba
35 On those filesystems this module provides a way to perform those
36 operations safely.
38 most of the performance loss with this module is in fsync on close().
39 You can disable that with
40 syncops:onclose = no
41 that can be set either globally or per share.
43 On certain filesystems that only require the last data written to be
44 fsync()'ed, you can disable the metadata synchronization of this module with
45 syncops:onmeta = no
46 This option can be set either globally or per share.
48 you can also disable the module completely for a share with
49 syncops:disable = true
53 struct syncops_config_data {
54 bool onclose;
55 bool onmeta;
56 bool disable;
60 given a filename, find the parent directory
62 static char *parent_dir(TALLOC_CTX *mem_ctx, const char *name)
64 const char *p = strrchr(name, '/');
65 if (p == NULL) {
66 return talloc_strdup(mem_ctx, ".");
68 return talloc_strndup(mem_ctx, name, (p+1) - name);
72 fsync a directory by name
74 static void syncops_sync_directory(connection_struct *conn,
75 char *dname)
77 struct smb_Dir *dir_hnd = NULL;
78 struct files_struct *dirfsp = NULL;
79 struct smb_filename smb_dname = { .base_name = dname };
80 NTSTATUS status;
82 status = OpenDir(talloc_tos(),
83 conn,
84 &smb_dname,
85 "*",
87 &dir_hnd);
88 if (!NT_STATUS_IS_OK(status)) {
89 errno = map_errno_from_nt_status(status);
90 return;
93 dirfsp = dir_hnd_fetch_fsp(dir_hnd);
95 smb_vfs_fsync_sync(dirfsp);
97 TALLOC_FREE(dir_hnd);
101 sync two meta data changes for 2 names
103 static void syncops_two_names(connection_struct *conn,
104 const struct smb_filename *name1,
105 const struct smb_filename *name2)
107 TALLOC_CTX *tmp_ctx = talloc_new(NULL);
108 char *parent1, *parent2;
109 parent1 = parent_dir(tmp_ctx, name1->base_name);
110 parent2 = parent_dir(tmp_ctx, name2->base_name);
111 if (!parent1 || !parent2) {
112 talloc_free(tmp_ctx);
113 return;
115 syncops_sync_directory(conn, parent1);
116 if (strcmp(parent1, parent2) != 0) {
117 syncops_sync_directory(conn, parent2);
119 talloc_free(tmp_ctx);
123 sync two meta data changes for 1 names
125 static void syncops_smb_fname(connection_struct *conn,
126 const struct smb_filename *smb_fname)
128 char *parent = NULL;
129 if (smb_fname != NULL) {
130 parent = parent_dir(NULL, smb_fname->base_name);
131 if (parent != NULL) {
132 syncops_sync_directory(conn, parent);
133 talloc_free(parent);
140 renameat needs special handling, as we may need to fsync two directories
142 static int syncops_renameat(vfs_handle_struct *handle,
143 files_struct *srcfsp,
144 const struct smb_filename *smb_fname_src,
145 files_struct *dstfsp,
146 const struct smb_filename *smb_fname_dst)
149 int ret;
150 struct smb_filename *full_fname_src = NULL;
151 struct smb_filename *full_fname_dst = NULL;
152 struct syncops_config_data *config;
154 SMB_VFS_HANDLE_GET_DATA(handle, config,
155 struct syncops_config_data,
156 return -1);
158 ret = SMB_VFS_NEXT_RENAMEAT(handle,
159 srcfsp,
160 smb_fname_src,
161 dstfsp,
162 smb_fname_dst);
163 if (ret == -1) {
164 return ret;
166 if (config->disable) {
167 return ret;
169 if (!config->onmeta) {
170 return ret;
173 full_fname_src = full_path_from_dirfsp_atname(talloc_tos(),
174 srcfsp,
175 smb_fname_src);
176 if (full_fname_src == NULL) {
177 errno = ENOMEM;
178 return ret;
180 full_fname_dst = full_path_from_dirfsp_atname(talloc_tos(),
181 dstfsp,
182 smb_fname_dst);
183 if (full_fname_dst == NULL) {
184 TALLOC_FREE(full_fname_src);
185 errno = ENOMEM;
186 return ret;
188 syncops_two_names(handle->conn,
189 full_fname_src,
190 full_fname_dst);
191 TALLOC_FREE(full_fname_src);
192 TALLOC_FREE(full_fname_dst);
193 return ret;
196 #define SYNCOPS_NEXT_SMB_FNAME(op, fname, args) do { \
197 int ret; \
198 struct smb_filename *full_fname = NULL; \
199 struct syncops_config_data *config; \
200 SMB_VFS_HANDLE_GET_DATA(handle, config, \
201 struct syncops_config_data, \
202 return -1); \
203 ret = SMB_VFS_NEXT_ ## op args; \
204 if (ret != 0) { \
205 return ret; \
207 if (config->disable) { \
208 return ret; \
210 if (!config->onmeta) { \
211 return ret; \
213 full_fname = full_path_from_dirfsp_atname(talloc_tos(), \
214 dirfsp, \
215 smb_fname); \
216 if (full_fname == NULL) { \
217 return ret; \
219 syncops_smb_fname(dirfsp->conn, full_fname); \
220 TALLOC_FREE(full_fname); \
221 return ret; \
222 } while (0)
224 static int syncops_symlinkat(vfs_handle_struct *handle,
225 const struct smb_filename *link_contents,
226 struct files_struct *dirfsp,
227 const struct smb_filename *smb_fname)
229 SYNCOPS_NEXT_SMB_FNAME(SYMLINKAT,
230 smb_fname,
231 (handle,
232 link_contents,
233 dirfsp,
234 smb_fname));
237 static int syncops_linkat(vfs_handle_struct *handle,
238 files_struct *srcfsp,
239 const struct smb_filename *old_smb_fname,
240 files_struct *dstfsp,
241 const struct smb_filename *new_smb_fname,
242 int flags)
244 int ret;
245 struct syncops_config_data *config;
246 struct smb_filename *old_full_fname = NULL;
247 struct smb_filename *new_full_fname = NULL;
249 SMB_VFS_HANDLE_GET_DATA(handle, config,
250 struct syncops_config_data,
251 return -1);
253 ret = SMB_VFS_NEXT_LINKAT(handle,
254 srcfsp,
255 old_smb_fname,
256 dstfsp,
257 new_smb_fname,
258 flags);
260 if (ret == -1) {
261 return ret;
263 if (config->disable) {
264 return ret;
266 if (!config->onmeta) {
267 return ret;
270 old_full_fname = full_path_from_dirfsp_atname(talloc_tos(),
271 srcfsp,
272 old_smb_fname);
273 if (old_full_fname == NULL) {
274 return ret;
276 new_full_fname = full_path_from_dirfsp_atname(talloc_tos(),
277 dstfsp,
278 new_smb_fname);
279 if (new_full_fname == NULL) {
280 TALLOC_FREE(old_full_fname);
281 return ret;
283 syncops_two_names(handle->conn,
284 old_full_fname,
285 new_full_fname);
286 TALLOC_FREE(old_full_fname);
287 TALLOC_FREE(new_full_fname);
288 return ret;
291 static int syncops_openat(struct vfs_handle_struct *handle,
292 const struct files_struct *dirfsp,
293 const struct smb_filename *smb_fname,
294 struct files_struct *fsp,
295 const struct vfs_open_how *how)
297 SYNCOPS_NEXT_SMB_FNAME(OPENAT, (how->flags & O_CREAT ? smb_fname : NULL),
298 (handle, dirfsp, smb_fname, fsp, how));
301 static int syncops_unlinkat(vfs_handle_struct *handle,
302 files_struct *dirfsp,
303 const struct smb_filename *smb_fname,
304 int flags)
306 SYNCOPS_NEXT_SMB_FNAME(UNLINKAT,
307 smb_fname,
308 (handle,
309 dirfsp,
310 smb_fname,
311 flags));
314 static int syncops_mknodat(vfs_handle_struct *handle,
315 files_struct *dirfsp,
316 const struct smb_filename *smb_fname,
317 mode_t mode,
318 SMB_DEV_T dev)
320 SYNCOPS_NEXT_SMB_FNAME(MKNODAT,
321 smb_fname,
322 (handle,
323 dirfsp,
324 smb_fname,
325 mode,
326 dev));
329 static int syncops_mkdirat(vfs_handle_struct *handle,
330 struct files_struct *dirfsp,
331 const struct smb_filename *smb_fname,
332 mode_t mode)
334 SYNCOPS_NEXT_SMB_FNAME(MKDIRAT,
335 full_fname,
336 (handle,
337 dirfsp,
338 smb_fname,
339 mode));
342 /* close needs to be handled specially */
343 static int syncops_close(vfs_handle_struct *handle, files_struct *fsp)
345 struct syncops_config_data *config;
347 SMB_VFS_HANDLE_GET_DATA(handle, config,
348 struct syncops_config_data,
349 return -1);
351 if (fsp->fsp_flags.can_write && config->onclose) {
352 /* ideally we'd only do this if we have written some
353 data, but there is no flag for that in fsp yet. */
354 fsync(fsp_get_io_fd(fsp));
356 return SMB_VFS_NEXT_CLOSE(handle, fsp);
359 static int syncops_connect(struct vfs_handle_struct *handle, const char *service,
360 const char *user)
363 struct syncops_config_data *config;
364 int ret = SMB_VFS_NEXT_CONNECT(handle, service, user);
365 if (ret < 0) {
366 return ret;
369 config = talloc_zero(handle->conn, struct syncops_config_data);
370 if (!config) {
371 SMB_VFS_NEXT_DISCONNECT(handle);
372 DEBUG(0, ("talloc_zero() failed\n"));
373 return -1;
376 config->onclose = lp_parm_bool(SNUM(handle->conn), "syncops",
377 "onclose", true);
379 config->onmeta = lp_parm_bool(SNUM(handle->conn), "syncops",
380 "onmeta", true);
382 config->disable = lp_parm_bool(SNUM(handle->conn), "syncops",
383 "disable", false);
385 SMB_VFS_HANDLE_SET_DATA(handle, config,
386 NULL, struct syncops_config_data,
387 return -1);
389 return 0;
393 static struct vfs_fn_pointers vfs_syncops_fns = {
394 .connect_fn = syncops_connect,
395 .mkdirat_fn = syncops_mkdirat,
396 .openat_fn = syncops_openat,
397 .renameat_fn = syncops_renameat,
398 .unlinkat_fn = syncops_unlinkat,
399 .symlinkat_fn = syncops_symlinkat,
400 .linkat_fn = syncops_linkat,
401 .mknodat_fn = syncops_mknodat,
402 .close_fn = syncops_close,
405 static_decl_vfs;
406 NTSTATUS vfs_syncops_init(TALLOC_CTX *ctx)
408 NTSTATUS ret;
410 ret = smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "syncops",
411 &vfs_syncops_fns);
413 if (!NT_STATUS_IS_OK(ret))
414 return ret;
416 return ret;