2 * ensure meta data operations are performed synchronously
4 * Copyright (C) Andrew Tridgell 2007
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 Some filesystems (even some journaled filesystems) require that a
26 fsync() be performed on many meta data operations to ensure that the
27 operation is guaranteed to remain in the filesystem after a power
28 failure. This is particularly important for some cluster filesystems
29 which are participating in a node failover system with clustered
32 On those filesystems this module provides a way to perform those
37 most of the performance loss with this module is in fsync on close().
38 You can disable that with syncops:onclose = no
40 static bool sync_onclose
;
43 given a filename, find the parent directory
45 static char *parent_dir(TALLOC_CTX
*mem_ctx
, const char *name
)
47 const char *p
= strrchr(name
, '/');
49 return talloc_strdup(mem_ctx
, ".");
51 return talloc_strndup(mem_ctx
, name
, (p
+1) - name
);
55 fsync a directory by name
57 static void syncops_sync_directory(const char *dname
)
60 int fd
= open(dname
, O_DIRECTORY
|O_RDONLY
);
66 DIR *d
= opendir(dname
);
75 sync two meta data changes for 2 names
77 static void syncops_two_names(const char *name1
, const char *name2
)
79 TALLOC_CTX
*tmp_ctx
= talloc_new(NULL
);
80 char *parent1
, *parent2
;
81 parent1
= parent_dir(tmp_ctx
, name1
);
82 parent2
= parent_dir(tmp_ctx
, name2
);
83 if (!parent1
|| !parent2
) {
87 syncops_sync_directory(parent1
);
88 if (strcmp(parent1
, parent2
) != 0) {
89 syncops_sync_directory(parent2
);
95 sync two meta data changes for 1 names
97 static void syncops_name(const char *name
)
100 parent
= parent_dir(NULL
, name
);
102 syncops_sync_directory(parent
);
108 sync two meta data changes for 1 names
110 static void syncops_smb_fname(const struct smb_filename
*smb_fname
)
113 parent
= parent_dir(NULL
, smb_fname
->base_name
);
115 syncops_sync_directory(parent
);
122 rename needs special handling, as we may need to fsync two directories
124 static int syncops_rename(vfs_handle_struct
*handle
,
125 const struct smb_filename
*smb_fname_src
,
126 const struct smb_filename
*smb_fname_dst
)
128 int ret
= SMB_VFS_NEXT_RENAME(handle
, smb_fname_src
, smb_fname_dst
);
130 syncops_two_names(smb_fname_src
->base_name
,
131 smb_fname_dst
->base_name
);
136 /* handle the rest with a macro */
137 #define SYNCOPS_NEXT(op, fname, args) do { \
138 int ret = SMB_VFS_NEXT_ ## op args; \
139 if (ret == 0 && fname) syncops_name(fname); \
143 #define SYNCOPS_NEXT_SMB_FNAME(op, fname, args) do { \
144 int ret = SMB_VFS_NEXT_ ## op args; \
145 if (ret == 0 && fname) syncops_smb_fname(fname); \
149 static int syncops_symlink(vfs_handle_struct
*handle
,
150 const char *oldname
, const char *newname
)
152 SYNCOPS_NEXT(SYMLINK
, newname
, (handle
, oldname
, newname
));
155 static int syncops_link(vfs_handle_struct
*handle
,
156 const char *oldname
, const char *newname
)
158 SYNCOPS_NEXT(LINK
, newname
, (handle
, oldname
, newname
));
161 static int syncops_open(vfs_handle_struct
*handle
,
162 struct smb_filename
*smb_fname
, files_struct
*fsp
,
163 int flags
, mode_t mode
)
165 SYNCOPS_NEXT_SMB_FNAME(OPEN
, (flags
&O_CREAT
?smb_fname
:NULL
),
166 (handle
, smb_fname
, fsp
, flags
, mode
));
169 static int syncops_unlink(vfs_handle_struct
*handle
,
170 const struct smb_filename
*smb_fname
)
172 SYNCOPS_NEXT_SMB_FNAME(UNLINK
, smb_fname
, (handle
, smb_fname
));
175 static int syncops_mknod(vfs_handle_struct
*handle
,
176 const char *fname
, mode_t mode
, SMB_DEV_T dev
)
178 SYNCOPS_NEXT(MKNOD
, fname
, (handle
, fname
, mode
, dev
));
181 static int syncops_mkdir(vfs_handle_struct
*handle
, const char *fname
, mode_t mode
)
183 SYNCOPS_NEXT(MKDIR
, fname
, (handle
, fname
, mode
));
186 static int syncops_rmdir(vfs_handle_struct
*handle
, const char *fname
)
188 SYNCOPS_NEXT(RMDIR
, fname
, (handle
, fname
));
191 /* close needs to be handled specially */
192 static int syncops_close(vfs_handle_struct
*handle
, files_struct
*fsp
)
194 if (fsp
->can_write
&& sync_onclose
) {
195 /* ideally we'd only do this if we have written some
196 data, but there is no flag for that in fsp yet. */
199 return SMB_VFS_NEXT_CLOSE(handle
, fsp
);
203 static struct vfs_fn_pointers vfs_syncops_fns
= {
204 .mkdir
= syncops_mkdir
,
205 .rmdir
= syncops_rmdir
,
206 .open
= syncops_open
,
207 .rename
= syncops_rename
,
208 .unlink
= syncops_unlink
,
209 .symlink
= syncops_symlink
,
210 .link
= syncops_link
,
211 .mknod
= syncops_mknod
,
212 .close_fn
= syncops_close
,
215 NTSTATUS
vfs_syncops_init(void)
219 ret
= smb_register_vfs(SMB_VFS_INTERFACE_VERSION
, "syncops",
222 if (!NT_STATUS_IS_OK(ret
))
225 sync_onclose
= lp_parm_bool(-1, "syncops", "onclose", true);