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