r23508: Fix sync_file() to return NTSTATUS and return this
[sfrench/samba-autobuild/.git] / source / 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 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 #if !defined(HAVE_LINUX_READAHEAD) && !defined(HAVE_POSIX_FADVISE)
22 static BOOL didmsg;
23 #endif
24
25 struct readahead_data {
26         SMB_OFF_T off_bound;
27         SMB_OFF_T len;
28         BOOL didmsg;
29 };
30
31 /* 
32  * This module copes with Vista AIO read requests on Linux
33  * by detecting the initial 0x80000 boundary reads and causing
34  * the buffer cache to be filled in advance.
35  */
36
37 /*******************************************************************
38  sendfile wrapper that does readahead/posix_fadvise.
39 *******************************************************************/
40
41 static ssize_t readahead_sendfile(struct vfs_handle_struct *handle,
42                                         int tofd,
43                                         files_struct *fsp,
44                                         int fromfd,
45                                         const DATA_BLOB *header,
46                                         SMB_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(fromfd, offset, (size_t)rhd->len);
54                 DEBUG(10,("readahead_sendfile: readahead on fd %u, offset %llu, len %u returned %d\n",
55                         (unsigned int)fromfd,
56                         (unsigned long long)offset,
57                         (unsigned int)rhd->len,
58                         err ));
59 #elif defined(HAVE_POSIX_FADVISE)
60                 int err = posix_fadvise(fromfd, 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)fromfd,
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                                         fsp,
76                                         fromfd,
77                                         header,
78                                         offset,
79                                         count);
80 }
81
82 /*******************************************************************
83  pread wrapper that does readahead/posix_fadvise.
84 *******************************************************************/
85
86 static ssize_t readahead_pread(vfs_handle_struct *handle,
87                                 files_struct *fsp,
88                                 int fd,
89                                 void *data,
90                                 size_t count,
91                                 SMB_OFF_T offset)
92 {
93         struct readahead_data *rhd = (struct readahead_data *)handle->data;
94
95         if ( offset % rhd->off_bound == 0) {
96 #if defined(HAVE_LINUX_READAHEAD)
97                 int err = readahead(fd, offset, (size_t)rhd->len);
98                 DEBUG(10,("readahead_pread: readahead on fd %u, offset %llu, len %u returned %d\n",
99                         (unsigned int)fd,
100                         (unsigned long long)offset,
101                         (unsigned int)rhd->len,
102                         err ));
103 #elif defined(HAVE_POSIX_FADVISE)
104                 int err = posix_fadvise(fd, offset, (off_t)rhd->len, POSIX_FADV_WILLNEED);
105                 DEBUG(10,("readahead_pread: posix_fadvise on fd %u, offset %llu, len %u returned %d\n",
106                         (unsigned int)fd,
107                         (unsigned long long)offset,
108                         (unsigned int)rhd->len,
109                         err ));
110 #else
111                 if (!rhd->didmsg) {
112                         DEBUG(0,("readahead_pread: no readahead on this platform\n"));
113                         rhd->didmsg = True;
114                 }
115 #endif
116         }
117         return SMB_VFS_NEXT_PREAD(handle, fsp, fd, data, count, offset);
118 }
119
120 /*******************************************************************
121  Directly called from main smbd when freeing handle.
122 *******************************************************************/
123
124 static void free_readahead_data(void **pptr)
125 {
126         SAFE_FREE(*pptr);
127 }
128
129 /*******************************************************************
130  Allocate the handle specific data so we don't call the expensive
131  conv_str_size function for each sendfile/pread.
132 *******************************************************************/
133
134 static int readahead_connect(struct vfs_handle_struct *handle,
135                                 const char *service,
136                                 const char *user)
137 {
138         struct readahead_data *rhd = SMB_MALLOC_P(struct readahead_data);
139         if (!rhd) {
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 /*******************************************************************
167  Functions we're replacing.
168  We don't replace read as it isn't used from smbd to read file
169  data.
170 *******************************************************************/
171
172 static vfs_op_tuple readahead_ops [] =
173 {
174         {SMB_VFS_OP(readahead_sendfile), SMB_VFS_OP_SENDFILE, SMB_VFS_LAYER_TRANSPARENT},
175         {SMB_VFS_OP(readahead_pread), SMB_VFS_OP_PREAD, SMB_VFS_LAYER_TRANSPARENT},
176         {SMB_VFS_OP(readahead_connect), SMB_VFS_OP_CONNECT,  SMB_VFS_LAYER_TRANSPARENT},
177         {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP}
178 };
179
180 /*******************************************************************
181  Module initialization boilerplate.
182 *******************************************************************/
183
184 NTSTATUS vfs_readahead_init(void);
185 NTSTATUS vfs_readahead_init(void)
186 {
187         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "readahead", readahead_ops);
188 }