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