root/source3/modules/vfs_syncops.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. parent_dir
  2. syncops_sync_directory
  3. syncops_two_names
  4. syncops_name
  5. syncops_rename
  6. syncops_symlink
  7. syncops_link
  8. syncops_open
  9. syncops_unlink
  10. syncops_mknod
  11. syncops_mkdir
  12. syncops_rmdir
  13. syncops_close
  14. vfs_syncops_init

   1 /* 
   2  * ensure meta data operations are performed synchronously
   3  *
   4  * Copyright (C) Andrew Tridgell     2007
   5  *
   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.
  10  *  
  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.
  15  *  
  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.
  19  */
  20 
  21 #include "includes.h"
  22 
  23 /*
  24 
  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
  30   Samba
  31 
  32   On those filesystems this module provides a way to perform those
  33   operations safely.  
  34  */
  35 
  36 /*
  37   most of the performance loss with this module is in fsync on close(). 
  38   You can disable that with syncops:onclose = no
  39  */
  40 static bool sync_onclose;
  41 
  42 /*
  43   given a filename, find the parent directory
  44  */
  45 static char *parent_dir(TALLOC_CTX *mem_ctx, const char *name)
     /* [<][>][^][v][top][bottom][index][help] */
  46 {
  47         const char *p = strrchr(name, '/');
  48         if (p == NULL) {
  49                 return talloc_strdup(mem_ctx, ".");
  50         }
  51         return talloc_strndup(mem_ctx, name, (p+1) - name);
  52 }
  53 
  54 /*
  55   fsync a directory by name
  56  */
  57 static void syncops_sync_directory(const char *dname)
     /* [<][>][^][v][top][bottom][index][help] */
  58 {
  59 #ifdef O_DIRECTORY
  60         int fd = open(dname, O_DIRECTORY|O_RDONLY);
  61         if (fd != -1) {
  62                 fsync(fd);
  63                 close(fd);
  64         }
  65 #else
  66         DIR *d = opendir(dname);
  67         if (d != NULL) {
  68                 fsync(dirfd(d));
  69                 closedir(d);
  70         }
  71 #endif
  72 }
  73 
  74 /*
  75   sync two meta data changes for 2 names
  76  */
  77 static void syncops_two_names(const char *name1, const char *name2)
     /* [<][>][^][v][top][bottom][index][help] */
  78 {
  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) {
  84                 talloc_free(tmp_ctx);
  85                 return;
  86         }
  87         syncops_sync_directory(parent1);
  88         if (strcmp(parent1, parent2) != 0) {
  89                 syncops_sync_directory(parent2);                
  90         }
  91         talloc_free(tmp_ctx);
  92 }
  93 
  94 /*
  95   sync two meta data changes for 1 names
  96  */
  97 static void syncops_name(const char *name)
     /* [<][>][^][v][top][bottom][index][help] */
  98 {
  99         char *parent;
 100         parent = parent_dir(NULL, name);
 101         if (parent) {
 102                 syncops_sync_directory(parent);
 103                 talloc_free(parent);
 104         }
 105 }
 106 
 107 
 108 /*
 109   rename needs special handling, as we may need to fsync two directories
 110  */
 111 static int syncops_rename(vfs_handle_struct *handle,
     /* [<][>][^][v][top][bottom][index][help] */
 112                           const char *oldname, const char *newname)
 113 {
 114         int ret = SMB_VFS_NEXT_RENAME(handle, oldname, newname);
 115         if (ret == 0) {
 116                 syncops_two_names(oldname, newname);
 117         }
 118         return ret;
 119 }
 120 
 121 /* handle the rest with a macro */
 122 #define SYNCOPS_NEXT(op, fname, args) do {   \
 123         int ret = SMB_VFS_NEXT_ ## op args; \
 124         if (ret == 0 && fname) syncops_name(fname); \
 125         return ret; \
 126 } while (0)
 127 
 128 static int syncops_symlink(vfs_handle_struct *handle,
     /* [<][>][^][v][top][bottom][index][help] */
 129                            const char *oldname, const char *newname)
 130 {
 131         SYNCOPS_NEXT(SYMLINK, newname, (handle, oldname, newname));
 132 }
 133 
 134 static int syncops_link(vfs_handle_struct *handle,
     /* [<][>][^][v][top][bottom][index][help] */
 135                          const char *oldname, const char *newname)
 136 {
 137         SYNCOPS_NEXT(LINK, newname, (handle, oldname, newname));
 138 }
 139 
 140 static int syncops_open(vfs_handle_struct *handle,
     /* [<][>][^][v][top][bottom][index][help] */
 141                         const char *fname, files_struct *fsp, int flags, mode_t mode)
 142 {
 143         SYNCOPS_NEXT(OPEN, (flags&O_CREAT?fname:NULL), (handle, fname, fsp, flags, mode));
 144 }
 145 
 146 static int syncops_unlink(vfs_handle_struct *handle, const char *fname)
     /* [<][>][^][v][top][bottom][index][help] */
 147 {
 148         SYNCOPS_NEXT(UNLINK, fname, (handle, fname));
 149 }
 150 
 151 static int syncops_mknod(vfs_handle_struct *handle,
     /* [<][>][^][v][top][bottom][index][help] */
 152                          const char *fname, mode_t mode, SMB_DEV_T dev)
 153 {
 154         SYNCOPS_NEXT(MKNOD, fname, (handle, fname, mode, dev));
 155 }
 156 
 157 static int syncops_mkdir(vfs_handle_struct *handle,  const char *fname, mode_t mode)
     /* [<][>][^][v][top][bottom][index][help] */
 158 {
 159         SYNCOPS_NEXT(MKDIR, fname, (handle, fname, mode));
 160 }
 161 
 162 static int syncops_rmdir(vfs_handle_struct *handle,  const char *fname)
     /* [<][>][^][v][top][bottom][index][help] */
 163 {
 164         SYNCOPS_NEXT(RMDIR, fname, (handle, fname));
 165 }
 166 
 167 /* close needs to be handled specially */
 168 static int syncops_close(vfs_handle_struct *handle, files_struct *fsp)
     /* [<][>][^][v][top][bottom][index][help] */
 169 {
 170         if (fsp->can_write && sync_onclose) {
 171                 /* ideally we'd only do this if we have written some
 172                  data, but there is no flag for that in fsp yet. */
 173                 fsync(fsp->fh->fd);
 174         }
 175         return SMB_VFS_NEXT_CLOSE(handle, fsp);
 176 }
 177 
 178 
 179 /* VFS operations structure */
 180 
 181 static vfs_op_tuple syncops_ops[] = {
 182         /* directory operations */
 183         {SMB_VFS_OP(syncops_mkdir),       SMB_VFS_OP_MKDIR,       SMB_VFS_LAYER_TRANSPARENT},
 184         {SMB_VFS_OP(syncops_rmdir),       SMB_VFS_OP_RMDIR,       SMB_VFS_LAYER_TRANSPARENT},
 185 
 186         /* File operations */
 187         {SMB_VFS_OP(syncops_open),       SMB_VFS_OP_OPEN,     SMB_VFS_LAYER_TRANSPARENT},
 188         {SMB_VFS_OP(syncops_rename),     SMB_VFS_OP_RENAME,   SMB_VFS_LAYER_TRANSPARENT},
 189         {SMB_VFS_OP(syncops_unlink),     SMB_VFS_OP_UNLINK,   SMB_VFS_LAYER_TRANSPARENT},
 190         {SMB_VFS_OP(syncops_symlink),    SMB_VFS_OP_SYMLINK,  SMB_VFS_LAYER_TRANSPARENT},
 191         {SMB_VFS_OP(syncops_link),       SMB_VFS_OP_LINK,     SMB_VFS_LAYER_TRANSPARENT},
 192         {SMB_VFS_OP(syncops_mknod),      SMB_VFS_OP_MKNOD,    SMB_VFS_LAYER_TRANSPARENT},
 193         {SMB_VFS_OP(syncops_close),      SMB_VFS_OP_CLOSE,    SMB_VFS_LAYER_TRANSPARENT},
 194 
 195         {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP}
 196 };
 197 
 198 NTSTATUS vfs_syncops_init(void)
     /* [<][>][^][v][top][bottom][index][help] */
 199 {
 200         NTSTATUS ret;
 201 
 202         ret = smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "syncops", syncops_ops);
 203 
 204         if (!NT_STATUS_IS_OK(ret))
 205                 return ret;
 206 
 207         sync_onclose = lp_parm_bool(-1, "syncops", "onclose", true);
 208         
 209         return ret;
 210 }

/* [<][>][^][v][top][bottom][index][help] */