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