s3: VFS: Change SMB_VFS_LINK to use const struct smb_filename * instead of const...
[Samba.git] / source3 / modules / vfs_syncops.c
blob725bd1072e42833f774ebcef80b4843e1e3e04f9
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_name(const char *name)
116 char *parent;
117 parent = parent_dir(NULL, name);
118 if (parent) {
119 syncops_sync_directory(parent);
120 talloc_free(parent);
125 sync two meta data changes for 1 names
127 static void syncops_smb_fname(const struct smb_filename *smb_fname)
129 char *parent;
130 parent = parent_dir(NULL, smb_fname->base_name);
131 if (parent) {
132 syncops_sync_directory(parent);
133 talloc_free(parent);
139 rename needs special handling, as we may need to fsync two directories
141 static int syncops_rename(vfs_handle_struct *handle,
142 const struct smb_filename *smb_fname_src,
143 const struct smb_filename *smb_fname_dst)
146 int ret;
147 struct syncops_config_data *config;
149 SMB_VFS_HANDLE_GET_DATA(handle, config,
150 struct syncops_config_data,
151 return -1);
153 ret = SMB_VFS_NEXT_RENAME(handle, smb_fname_src, smb_fname_dst);
154 if (ret == 0 && config->onmeta && !config->disable) {
155 syncops_two_names(smb_fname_src->base_name,
156 smb_fname_dst->base_name);
158 return ret;
161 /* handle the rest with a macro */
162 #define SYNCOPS_NEXT(op, fname, args) do { \
163 int ret; \
164 struct syncops_config_data *config; \
165 SMB_VFS_HANDLE_GET_DATA(handle, config, \
166 struct syncops_config_data, \
167 return -1); \
168 ret = SMB_VFS_NEXT_ ## op args; \
169 if (ret == 0 \
170 && config->onmeta && !config->disable \
171 && fname) syncops_name(fname); \
172 return ret; \
173 } while (0)
175 #define SYNCOPS_NEXT_SMB_FNAME(op, fname, args) do { \
176 int ret; \
177 struct syncops_config_data *config; \
178 SMB_VFS_HANDLE_GET_DATA(handle, config, \
179 struct syncops_config_data, \
180 return -1); \
181 ret = SMB_VFS_NEXT_ ## op args; \
182 if (ret == 0 \
183 && config->onmeta && !config->disable \
184 && fname) syncops_smb_fname(fname); \
185 return ret; \
186 } while (0)
188 static int syncops_symlink(vfs_handle_struct *handle,
189 const char *oldname, const char *newname)
191 SYNCOPS_NEXT(SYMLINK, newname, (handle, oldname, newname));
194 static int syncops_link(vfs_handle_struct *handle,
195 const struct smb_filename *old_smb_fname,
196 const struct smb_filename *new_smb_fname)
198 int ret;
199 struct syncops_config_data *config;
201 SMB_VFS_HANDLE_GET_DATA(handle, config,
202 struct syncops_config_data,
203 return -1);
205 ret = SMB_VFS_NEXT_LINK(handle, old_smb_fname, new_smb_fname);
206 if (ret == 0 && config->onmeta && !config->disable) {
207 syncops_two_names(old_smb_fname->base_name,
208 new_smb_fname->base_name);
210 return ret;
213 static int syncops_open(vfs_handle_struct *handle,
214 struct smb_filename *smb_fname, files_struct *fsp,
215 int flags, mode_t mode)
217 SYNCOPS_NEXT_SMB_FNAME(OPEN, (flags&O_CREAT?smb_fname:NULL),
218 (handle, smb_fname, fsp, flags, mode));
221 static int syncops_unlink(vfs_handle_struct *handle,
222 const struct smb_filename *smb_fname)
224 SYNCOPS_NEXT_SMB_FNAME(UNLINK, smb_fname, (handle, smb_fname));
227 static int syncops_mknod(vfs_handle_struct *handle,
228 const struct smb_filename *smb_fname,
229 mode_t mode,
230 SMB_DEV_T dev)
232 SYNCOPS_NEXT_SMB_FNAME(MKNOD,
233 smb_fname, (handle, smb_fname, mode, dev));
236 static int syncops_mkdir(vfs_handle_struct *handle,
237 const struct smb_filename *smb_fname,
238 mode_t mode)
240 SYNCOPS_NEXT_SMB_FNAME(MKDIR, smb_fname, (handle, smb_fname, mode));
243 static int syncops_rmdir(vfs_handle_struct *handle,
244 const struct smb_filename *smb_fname)
246 SYNCOPS_NEXT_SMB_FNAME(RMDIR, smb_fname, (handle, smb_fname));
249 /* close needs to be handled specially */
250 static int syncops_close(vfs_handle_struct *handle, files_struct *fsp)
252 struct syncops_config_data *config;
254 SMB_VFS_HANDLE_GET_DATA(handle, config,
255 struct syncops_config_data,
256 return -1);
258 if (fsp->can_write && config->onclose) {
259 /* ideally we'd only do this if we have written some
260 data, but there is no flag for that in fsp yet. */
261 fsync(fsp->fh->fd);
263 return SMB_VFS_NEXT_CLOSE(handle, fsp);
266 static int syncops_connect(struct vfs_handle_struct *handle, const char *service,
267 const char *user)
270 struct syncops_config_data *config;
271 int ret = SMB_VFS_NEXT_CONNECT(handle, service, user);
272 if (ret < 0) {
273 return ret;
276 config = talloc_zero(handle->conn, struct syncops_config_data);
277 if (!config) {
278 SMB_VFS_NEXT_DISCONNECT(handle);
279 DEBUG(0, ("talloc_zero() failed\n"));
280 return -1;
283 config->onclose = lp_parm_bool(SNUM(handle->conn), "syncops",
284 "onclose", true);
286 config->onmeta = lp_parm_bool(SNUM(handle->conn), "syncops",
287 "onmeta", true);
289 config->disable = lp_parm_bool(SNUM(handle->conn), "syncops",
290 "disable", false);
292 SMB_VFS_HANDLE_SET_DATA(handle, config,
293 NULL, struct syncops_config_data,
294 return -1);
296 return 0;
300 static struct vfs_fn_pointers vfs_syncops_fns = {
301 .connect_fn = syncops_connect,
302 .mkdir_fn = syncops_mkdir,
303 .rmdir_fn = syncops_rmdir,
304 .open_fn = syncops_open,
305 .rename_fn = syncops_rename,
306 .unlink_fn = syncops_unlink,
307 .symlink_fn = syncops_symlink,
308 .link_fn = syncops_link,
309 .mknod_fn = syncops_mknod,
310 .close_fn = syncops_close,
313 static_decl_vfs;
314 NTSTATUS vfs_syncops_init(TALLOC_CTX *ctx)
316 NTSTATUS ret;
318 ret = smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "syncops",
319 &vfs_syncops_fns);
321 if (!NT_STATUS_IS_OK(ret))
322 return ret;
324 return ret;