r16945: Sync trunk -> 3.0 for 3.0.24 code. Still need
[ira/wip.git] / source3 / modules / vfs_commit.c
1 /*
2  * Copyright (c) James Peach 2006
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18
19 #include "includes.h"
20
21 /* Commit data module.
22  *
23  * The purpose of this module is to flush data to disk at regular intervals,
24  * just like the NFS commit operation. There's two rationales for this. First,
25  * it minimises the data loss in case of a power outage without incurring
26  * the poor performance of synchronous I/O. Second, a steady flush rate
27  * can produce better throughput than suddenly dumping massive amounts of
28  * writes onto a disk.
29  *
30  * Tunables:
31  *
32  *  commit: dthresh         Amount of dirty data that can accumulate
33  *                                      before we commit (sync) it.
34  *
35  *  commit: debug           Debug level at which to emit messages.
36  *
37  */
38
39 #define MODULE "commit"
40
41 static int module_debug;
42
43 struct commit_info
44 {
45         SMB_OFF_T dbytes;       /* Dirty (uncommitted) bytes */
46         SMB_OFF_T dthresh;      /* Dirty data threshold */
47 };
48
49 static void commit_all(
50         struct vfs_handle_struct *      handle,
51         files_struct *                  fsp)
52 {
53         struct commit_info *c;
54
55         if ((c = VFS_FETCH_FSP_EXTENSION(handle, fsp))) {
56                 if (c->dbytes) {
57                         DEBUG(module_debug,
58                                 ("%s: flushing %lu dirty bytes\n",
59                                  MODULE, (unsigned long)c->dbytes));
60
61                         fdatasync(fsp->fh->fd);
62                         c->dbytes = 0;
63                 }
64         }
65 }
66
67 static void commit(
68         struct vfs_handle_struct *      handle,
69         files_struct *                  fsp,
70         ssize_t                         last_write)
71 {
72         struct commit_info *c;
73
74         if ((c = VFS_FETCH_FSP_EXTENSION(handle, fsp))) {
75
76                 if (last_write > 0) {
77                         c->dbytes += last_write;
78                 }
79
80                 if (c->dbytes > c->dthresh) {
81                         DEBUG(module_debug,
82                                 ("%s: flushing %lu dirty bytes\n",
83                                  MODULE, (unsigned long)c->dbytes));
84
85                         fdatasync(fsp->fh->fd);
86                         c->dbytes = 0;
87                 }
88         }
89 }
90
91 static int commit_connect(
92         struct vfs_handle_struct *  handle,
93         const char *                service,
94         const char *                user)
95 {
96         module_debug = lp_parm_int(SNUM(handle->conn), MODULE, "debug", 100);
97         return SMB_VFS_NEXT_CONNECT(handle, service, user);
98 }
99
100 static int commit_open(
101         vfs_handle_struct * handle,
102         const char *        fname,
103         files_struct *      fsp,
104         int                 flags,
105         mode_t              mode)
106 {
107         SMB_OFF_T dthresh;
108
109         /* Don't bother with read-only files. */
110         if ((flags & O_ACCMODE) == O_RDONLY) {
111                 return SMB_VFS_NEXT_OPEN(handle, fname, fsp, flags, mode);
112         }
113
114         dthresh = conv_str_size(lp_parm_const_string(SNUM(handle->conn),
115                                         MODULE, "dthresh", NULL));
116
117         if (dthresh > 0) {
118                 struct commit_info * c;
119                 c = VFS_ADD_FSP_EXTENSION(handle, fsp, struct commit_info);
120                 if (c) {
121                         c->dthresh = dthresh;
122                         c->dbytes = 0;
123                 }
124         }
125
126         return SMB_VFS_NEXT_OPEN(handle, fname, fsp, flags, mode);
127 }
128
129 static ssize_t commit_write(
130         vfs_handle_struct * handle,
131         files_struct *      fsp,
132         int                 fd,
133         void *              data,
134         size_t              count)
135 {
136         ssize_t ret;
137
138         ret = SMB_VFS_NEXT_WRITE(handle, fsp, fd, data, count);
139         commit(handle, fsp, ret);
140
141         return ret;
142 }
143
144 static ssize_t commit_pwrite(
145         vfs_handle_struct * handle,
146         files_struct *      fsp,
147         int                 fd,
148         void *              data,
149         size_t              count,
150         SMB_OFF_T           offset)
151 {
152         ssize_t ret;
153
154         ret = SMB_VFS_NEXT_PWRITE(handle, fsp, fd, data, count, offset);
155         commit(handle, fsp, ret);
156
157         return ret;
158 }
159
160 static ssize_t commit_close(
161         vfs_handle_struct * handle,
162         files_struct *      fsp,
163         int                 fd)
164 {
165         commit_all(handle, fsp);
166         return SMB_VFS_NEXT_CLOSE(handle, fsp, fd);
167 }
168
169 static vfs_op_tuple commit_ops [] =
170 {
171         {SMB_VFS_OP(commit_open),
172                 SMB_VFS_OP_OPEN, SMB_VFS_LAYER_TRANSPARENT},
173         {SMB_VFS_OP(commit_close),
174                 SMB_VFS_OP_CLOSE, SMB_VFS_LAYER_TRANSPARENT},
175         {SMB_VFS_OP(commit_write),
176                 SMB_VFS_OP_WRITE, SMB_VFS_LAYER_TRANSPARENT},
177         {SMB_VFS_OP(commit_pwrite),
178                 SMB_VFS_OP_PWRITE, SMB_VFS_LAYER_TRANSPARENT},
179         {SMB_VFS_OP(commit_connect),
180                 SMB_VFS_OP_CONNECT,  SMB_VFS_LAYER_TRANSPARENT},
181
182         {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP}
183 };
184
185 NTSTATUS vfs_commit_init(void)
186 {
187         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, MODULE, commit_ops);
188 }
189