Line data Source code
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 0 : 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 0 : struct readahead_data *rhd = (struct readahead_data *)handle->data;
50 :
51 0 : if ( offset % rhd->off_bound == 0) {
52 : #if defined(HAVE_LINUX_READAHEAD)
53 0 : int err = readahead(fsp_get_io_fd(fromfsp), offset, (size_t)rhd->len);
54 0 : DEBUG(10,("readahead_sendfile: readahead on fd %u, offset %llu, len %u returned %d\n",
55 : (unsigned int)fsp_get_io_fd(fromfsp),
56 : (unsigned long long)offset,
57 : (unsigned int)rhd->len,
58 : err ));
59 : #elif defined(HAVE_POSIX_FADVISE)
60 : int err = posix_fadvise(fsp_get_io_fd(fromfsp), 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)fsp_get_io_fd(fromfsp),
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 0 : 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 0 : 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 0 : struct readahead_data *rhd = (struct readahead_data *)handle->data;
92 :
93 0 : if ( offset % rhd->off_bound == 0) {
94 : #if defined(HAVE_LINUX_READAHEAD)
95 0 : int err = readahead(fsp_get_io_fd(fsp), offset, (size_t)rhd->len);
96 0 : DEBUG(10,("readahead_pread: readahead on fd %u, offset %llu, len %u returned %d\n",
97 : (unsigned int)fsp_get_io_fd(fsp),
98 : (unsigned long long)offset,
99 : (unsigned int)rhd->len,
100 : err ));
101 : #elif defined(HAVE_POSIX_FADVISE)
102 : int err = posix_fadvise(fsp_get_io_fd(fsp), 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_get_io_fd(fsp),
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 0 : 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 0 : static void free_readahead_data(void **pptr)
123 : {
124 0 : SAFE_FREE(*pptr);
125 0 : }
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 0 : static int readahead_connect(struct vfs_handle_struct *handle,
133 : const char *service,
134 : const char *user)
135 : {
136 : struct readahead_data *rhd;
137 0 : int ret = SMB_VFS_NEXT_CONNECT(handle, service, user);
138 :
139 0 : if (ret < 0) {
140 0 : return ret;
141 : }
142 0 : rhd = SMB_MALLOC_P(struct readahead_data);
143 0 : if (!rhd) {
144 0 : SMB_VFS_NEXT_DISCONNECT(handle);
145 0 : DEBUG(0,("readahead_connect: out of memory\n"));
146 0 : return -1;
147 : }
148 0 : ZERO_STRUCTP(rhd);
149 :
150 0 : rhd->didmsg = False;
151 0 : rhd->off_bound = conv_str_size(lp_parm_const_string(SNUM(handle->conn),
152 : "readahead",
153 : "offset",
154 : NULL));
155 0 : if (rhd->off_bound == 0) {
156 0 : rhd->off_bound = 0x80000;
157 : }
158 0 : rhd->len = conv_str_size(lp_parm_const_string(SNUM(handle->conn),
159 : "readahead",
160 : "length",
161 : NULL));
162 0 : if (rhd->len == 0) {
163 0 : rhd->len = rhd->off_bound;
164 : }
165 :
166 0 : handle->data = (void *)rhd;
167 0 : handle->free_data = free_readahead_data;
168 0 : 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 : static_decl_vfs;
182 27 : NTSTATUS vfs_readahead_init(TALLOC_CTX *ctx)
183 : {
184 27 : return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "readahead",
185 : &vfs_readahead_fns);
186 : }
|