s3-includes: only include system/filesys.h when needed.
[ira/wip.git] / source3 / modules / vfs_readahead.c
1 /*
2  * Copyright (c) Jeremy Allison 2007.
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 3 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, see <http://www.gnu.org/licenses/>.
16  */
17
18 #include "includes.h"
19 #include "system/filesys.h"
20
21 struct readahead_data {
22         SMB_OFF_T off_bound;
23         SMB_OFF_T len;
24         bool didmsg;
25 };
26
27 /* 
28  * This module copes with Vista AIO read requests on Linux
29  * by detecting the initial 0x80000 boundary reads and causing
30  * the buffer cache to be filled in advance.
31  */
32
33 /*******************************************************************
34  sendfile wrapper that does readahead/posix_fadvise.
35 *******************************************************************/
36
37 static ssize_t readahead_sendfile(struct vfs_handle_struct *handle,
38                                         int tofd,
39                                         files_struct *fromfsp,
40                                         const DATA_BLOB *header,
41                                         SMB_OFF_T offset,
42                                         size_t count)
43 {
44         struct readahead_data *rhd = (struct readahead_data *)handle->data;
45
46         if ( offset % rhd->off_bound == 0) {
47 #if defined(HAVE_LINUX_READAHEAD)
48                 int err = readahead(fromfsp->fh->fd, offset, (size_t)rhd->len);
49                 DEBUG(10,("readahead_sendfile: readahead on fd %u, offset %llu, len %u returned %d\n",
50                         (unsigned int)fromfsp->fh->fd,
51                         (unsigned long long)offset,
52                         (unsigned int)rhd->len,
53                         err ));
54 #elif defined(HAVE_POSIX_FADVISE)
55                 int err = posix_fadvise(fromfsp->fh->fd, offset, (off_t)rhd->len, POSIX_FADV_WILLNEED);
56                 DEBUG(10,("readahead_sendfile: posix_fadvise on fd %u, offset %llu, len %u returned %d\n",
57                         (unsigned int)fromfsp->fh->fd,
58                         (unsigned long long)offset,
59                         (unsigned int)rhd->len,
60                         err ));
61 #else
62                 if (!rhd->didmsg) {
63                         DEBUG(0,("readahead_sendfile: no readahead on this platform\n"));
64                         rhd->didmsg = True;
65                 }
66 #endif
67         }
68         return SMB_VFS_NEXT_SENDFILE(handle,
69                                         tofd,
70                                         fromfsp,
71                                         header,
72                                         offset,
73                                         count);
74 }
75
76 /*******************************************************************
77  pread wrapper that does readahead/posix_fadvise.
78 *******************************************************************/
79
80 static ssize_t readahead_pread(vfs_handle_struct *handle,
81                                 files_struct *fsp,
82                                 void *data,
83                                 size_t count,
84                                 SMB_OFF_T offset)
85 {
86         struct readahead_data *rhd = (struct readahead_data *)handle->data;
87
88         if ( offset % rhd->off_bound == 0) {
89 #if defined(HAVE_LINUX_READAHEAD)
90                 int err = readahead(fsp->fh->fd, offset, (size_t)rhd->len);
91                 DEBUG(10,("readahead_pread: readahead on fd %u, offset %llu, len %u returned %d\n",
92                         (unsigned int)fsp->fh->fd,
93                         (unsigned long long)offset,
94                         (unsigned int)rhd->len,
95                         err ));
96 #elif defined(HAVE_POSIX_FADVISE)
97                 int err = posix_fadvise(fsp->fh->fd, offset, (off_t)rhd->len, POSIX_FADV_WILLNEED);
98                 DEBUG(10,("readahead_pread: posix_fadvise on fd %u, offset %llu, len %u returned %d\n",
99                         (unsigned int)fsp->fh->fd,
100                         (unsigned long long)offset,
101                         (unsigned int)rhd->len,
102                         err ));
103 #else
104                 if (!rhd->didmsg) {
105                         DEBUG(0,("readahead_pread: no readahead on this platform\n"));
106                         rhd->didmsg = True;
107                 }
108 #endif
109         }
110         return SMB_VFS_NEXT_PREAD(handle, fsp, data, count, offset);
111 }
112
113 /*******************************************************************
114  Directly called from main smbd when freeing handle.
115 *******************************************************************/
116
117 static void free_readahead_data(void **pptr)
118 {
119         SAFE_FREE(*pptr);
120 }
121
122 /*******************************************************************
123  Allocate the handle specific data so we don't call the expensive
124  conv_str_size function for each sendfile/pread.
125 *******************************************************************/
126
127 static int readahead_connect(struct vfs_handle_struct *handle,
128                                 const char *service,
129                                 const char *user)
130 {
131         struct readahead_data *rhd;
132         int ret = SMB_VFS_NEXT_CONNECT(handle, service, user);
133
134         if (ret < 0) {
135                 return ret;
136         }
137         rhd = SMB_MALLOC_P(struct readahead_data);
138         if (!rhd) {
139                 SMB_VFS_NEXT_DISCONNECT(handle);
140                 DEBUG(0,("readahead_connect: out of memory\n"));
141                 return -1;
142         }
143         ZERO_STRUCTP(rhd);
144
145         rhd->didmsg = False;
146         rhd->off_bound = conv_str_size(lp_parm_const_string(SNUM(handle->conn),
147                                                 "readahead",
148                                                 "offset",
149                                                 NULL));
150         if (rhd->off_bound == 0) {
151                 rhd->off_bound = 0x80000;
152         }
153         rhd->len = conv_str_size(lp_parm_const_string(SNUM(handle->conn),
154                                                 "readahead",
155                                                 "length",
156                                                 NULL));
157         if (rhd->len == 0) {
158                 rhd->len = rhd->off_bound;
159         }
160
161         handle->data = (void *)rhd;
162         handle->free_data = free_readahead_data;
163         return 0;
164 }
165
166 static struct vfs_fn_pointers vfs_readahead_fns = {
167         .sendfile = readahead_sendfile,
168         .pread = readahead_pread,
169         .connect_fn = readahead_connect
170 };
171
172 /*******************************************************************
173  Module initialization boilerplate.
174 *******************************************************************/
175
176 NTSTATUS vfs_readahead_init(void);
177 NTSTATUS vfs_readahead_init(void)
178 {
179         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "readahead",
180                                 &vfs_readahead_fns);
181 }