s4:selftest: explicitly set NSS/RESOLV_WAPPER_* in wait_for_start
[Samba.git] / source3 / modules / vfs_syncops.c
blobf94588c60ed09edfe2b8f0feb320678613ab82b6
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(const char *dname)
76 #ifdef O_DIRECTORY
77 int fd = open(dname, O_DIRECTORY|O_RDONLY);
78 if (fd != -1) {
79 fsync(fd);
80 close(fd);
82 #else
83 DIR *d = opendir(dname);
84 if (d != NULL) {
85 fsync(dirfd(d));
86 closedir(d);
88 #endif
92 sync two meta data changes for 2 names
94 static void syncops_two_names(const char *name1, const char *name2)
96 TALLOC_CTX *tmp_ctx = talloc_new(NULL);
97 char *parent1, *parent2;
98 parent1 = parent_dir(tmp_ctx, name1);
99 parent2 = parent_dir(tmp_ctx, name2);
100 if (!parent1 || !parent2) {
101 talloc_free(tmp_ctx);
102 return;
104 syncops_sync_directory(parent1);
105 if (strcmp(parent1, parent2) != 0) {
106 syncops_sync_directory(parent2);
108 talloc_free(tmp_ctx);
112 sync two meta data changes for 1 names
114 static void syncops_smb_fname(const struct smb_filename *smb_fname)
116 char *parent;
117 parent = parent_dir(NULL, smb_fname->base_name);
118 if (parent) {
119 syncops_sync_directory(parent);
120 talloc_free(parent);
126 rename needs special handling, as we may need to fsync two directories
128 static int syncops_rename(vfs_handle_struct *handle,
129 const struct smb_filename *smb_fname_src,
130 const struct smb_filename *smb_fname_dst)
133 int ret;
134 struct syncops_config_data *config;
136 SMB_VFS_HANDLE_GET_DATA(handle, config,
137 struct syncops_config_data,
138 return -1);
140 ret = SMB_VFS_NEXT_RENAME(handle, smb_fname_src, smb_fname_dst);
141 if (ret == 0 && config->onmeta && !config->disable) {
142 syncops_two_names(smb_fname_src->base_name,
143 smb_fname_dst->base_name);
145 return ret;
148 #define SYNCOPS_NEXT_SMB_FNAME(op, fname, args) do { \
149 int ret; \
150 struct syncops_config_data *config; \
151 SMB_VFS_HANDLE_GET_DATA(handle, config, \
152 struct syncops_config_data, \
153 return -1); \
154 ret = SMB_VFS_NEXT_ ## op args; \
155 if (ret == 0 \
156 && config->onmeta && !config->disable \
157 && fname) syncops_smb_fname(fname); \
158 return ret; \
159 } while (0)
161 static int syncops_symlink(vfs_handle_struct *handle,
162 const char *link_contents,
163 const struct smb_filename *new_smb_fname)
165 int ret;
166 struct syncops_config_data *config;
168 SMB_VFS_HANDLE_GET_DATA(handle, config,
169 struct syncops_config_data,
170 return -1);
172 ret = SMB_VFS_NEXT_SYMLINK(handle, link_contents, new_smb_fname);
173 if (ret == 0 && config->onmeta && !config->disable) {
174 syncops_two_names(link_contents,
175 new_smb_fname->base_name);
177 return ret;
180 static int syncops_link(vfs_handle_struct *handle,
181 const struct smb_filename *old_smb_fname,
182 const struct smb_filename *new_smb_fname)
184 int ret;
185 struct syncops_config_data *config;
187 SMB_VFS_HANDLE_GET_DATA(handle, config,
188 struct syncops_config_data,
189 return -1);
191 ret = SMB_VFS_NEXT_LINK(handle, old_smb_fname, new_smb_fname);
192 if (ret == 0 && config->onmeta && !config->disable) {
193 syncops_two_names(old_smb_fname->base_name,
194 new_smb_fname->base_name);
196 return ret;
199 static int syncops_open(vfs_handle_struct *handle,
200 struct smb_filename *smb_fname, files_struct *fsp,
201 int flags, mode_t mode)
203 SYNCOPS_NEXT_SMB_FNAME(OPEN, (flags&O_CREAT?smb_fname:NULL),
204 (handle, smb_fname, fsp, flags, mode));
207 static int syncops_unlink(vfs_handle_struct *handle,
208 const struct smb_filename *smb_fname)
210 SYNCOPS_NEXT_SMB_FNAME(UNLINK, smb_fname, (handle, smb_fname));
213 static int syncops_mknod(vfs_handle_struct *handle,
214 const struct smb_filename *smb_fname,
215 mode_t mode,
216 SMB_DEV_T dev)
218 SYNCOPS_NEXT_SMB_FNAME(MKNOD,
219 smb_fname, (handle, smb_fname, mode, dev));
222 static int syncops_mkdir(vfs_handle_struct *handle,
223 const struct smb_filename *smb_fname,
224 mode_t mode)
226 SYNCOPS_NEXT_SMB_FNAME(MKDIR, smb_fname, (handle, smb_fname, mode));
229 static int syncops_rmdir(vfs_handle_struct *handle,
230 const struct smb_filename *smb_fname)
232 SYNCOPS_NEXT_SMB_FNAME(RMDIR, smb_fname, (handle, smb_fname));
235 /* close needs to be handled specially */
236 static int syncops_close(vfs_handle_struct *handle, files_struct *fsp)
238 struct syncops_config_data *config;
240 SMB_VFS_HANDLE_GET_DATA(handle, config,
241 struct syncops_config_data,
242 return -1);
244 if (fsp->can_write && config->onclose) {
245 /* ideally we'd only do this if we have written some
246 data, but there is no flag for that in fsp yet. */
247 fsync(fsp->fh->fd);
249 return SMB_VFS_NEXT_CLOSE(handle, fsp);
252 static int syncops_connect(struct vfs_handle_struct *handle, const char *service,
253 const char *user)
256 struct syncops_config_data *config;
257 int ret = SMB_VFS_NEXT_CONNECT(handle, service, user);
258 if (ret < 0) {
259 return ret;
262 config = talloc_zero(handle->conn, struct syncops_config_data);
263 if (!config) {
264 SMB_VFS_NEXT_DISCONNECT(handle);
265 DEBUG(0, ("talloc_zero() failed\n"));
266 return -1;
269 config->onclose = lp_parm_bool(SNUM(handle->conn), "syncops",
270 "onclose", true);
272 config->onmeta = lp_parm_bool(SNUM(handle->conn), "syncops",
273 "onmeta", true);
275 config->disable = lp_parm_bool(SNUM(handle->conn), "syncops",
276 "disable", false);
278 SMB_VFS_HANDLE_SET_DATA(handle, config,
279 NULL, struct syncops_config_data,
280 return -1);
282 return 0;
286 static struct vfs_fn_pointers vfs_syncops_fns = {
287 .connect_fn = syncops_connect,
288 .mkdir_fn = syncops_mkdir,
289 .rmdir_fn = syncops_rmdir,
290 .open_fn = syncops_open,
291 .rename_fn = syncops_rename,
292 .unlink_fn = syncops_unlink,
293 .symlink_fn = syncops_symlink,
294 .link_fn = syncops_link,
295 .mknod_fn = syncops_mknod,
296 .close_fn = syncops_close,
299 static_decl_vfs;
300 NTSTATUS vfs_syncops_init(TALLOC_CTX *ctx)
302 NTSTATUS ret;
304 ret = smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "syncops",
305 &vfs_syncops_fns);
307 if (!NT_STATUS_IS_OK(ret))
308 return ret;
310 return ret;