r22105: Added vfs_readahead module that appears to do wonderful things
[obnox/samba/samba-obnox.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 /* 
26  * This module copes with Vista AIO read requests on Linux
27  * by detecting the initial 0x80000 boundary reads and causing
28  * the buffer cache to be filled in advance.
29  */
30
31 static ssize_t readahead_sendfile(struct vfs_handle_struct *handle,
32                                         int tofd,
33                                         files_struct *fsp,
34                                         int fromfd,
35                                         const DATA_BLOB *header,
36                                         SMB_OFF_T offset,
37                                         size_t count)
38 {
39         unsigned long off_bound = lp_parm_ulong(SNUM(handle->conn), "readahead", "offset", 0x80000);
40         if ( offset % off_bound == 0) {
41                 unsigned long len = lp_parm_ulong(SNUM(handle->conn), "readahead", "length", off_bound);
42 #if defined(HAVE_LINUX_READAHEAD)
43                 int err = readahead(fromfd, offset, (size_t)len);
44                 DEBUG(10,("readahead_sendfile: readahead on fd %u, offset %llu, len %u returned %d\n",
45                         (unsigned int)fromfd,
46                         (unsigned long long)offset,
47                         (unsigned int)len,
48                         err ));
49 #elif defined(HAVE_POSIX_FADVISE)
50                 int err = posix_fadvise(fromfd, offset, (off_t)len, POSIX_FADV_WILLNEED);
51                 DEBUG(10,("readahead_sendfile: posix_fadvise on fd %u, offset %llu, len %u returned %d\n",
52                         (unsigned int)fromfd,
53                         (unsigned long long)offset,
54                         (unsigned int)len,
55                         err ));
56 #else
57                 if (!didmsg) {
58                         DEBUG(0,("readahead_sendfile: no readahead on this platform\n"));
59                         didmsg = True;
60                 }
61 #endif
62         }
63         return SMB_VFS_NEXT_SENDFILE(handle,
64                                         tofd,
65                                         fsp,
66                                         fromfd,
67                                         header,
68                                         offset,
69                                         count);
70 }
71
72 static ssize_t readahead_pread(vfs_handle_struct *handle,
73                                 files_struct *fsp,
74                                 int fd,
75                                 void *data,
76                                 size_t count,
77                                 SMB_OFF_T offset)
78 {
79         unsigned long off_bound = lp_parm_ulong(SNUM(handle->conn), "readahead", "offset", 0x80000);
80         if ( offset % off_bound == 0) {
81                 unsigned long len = lp_parm_ulong(SNUM(handle->conn), "readahead", "length", off_bound);
82 #if defined(HAVE_LINUX_READAHEAD)
83                 int err = readahead(fd, offset, (size_t)len);
84                 DEBUG(10,("readahead_pread: readahead on fd %u, offset %llu, len %u returned %d\n",
85                         (unsigned int)fd,
86                         (unsigned long long)offset,
87                         (unsigned int)len,
88                         err ));
89 #elif defined(HAVE_POSIX_FADVISE)
90                 int err = posix_fadvise(fromfd, offset, (off_t)len, POSIX_FADV_WILLNEED);
91                 DEBUG(10,("readahead_pread: posix_fadvise on fd %u, offset %llu, len %u returned %d\n",
92                         (unsigned int)fd,
93                         (unsigned long long)offset,
94                         (unsigned int)len,
95                         (err ));
96 #else
97                 if (!didmsg) {
98                         DEBUG(0,("readahead_pread: no readahead on this platform\n"));
99                         didmsg = True;
100                 }
101 #endif
102         }
103         return SMB_VFS_NEXT_PREAD(handle, fsp, fd, data, count, offset);
104 }
105
106 static vfs_op_tuple readahead_ops [] =
107 {
108         {SMB_VFS_OP(readahead_sendfile), SMB_VFS_OP_SENDFILE, SMB_VFS_LAYER_TRANSPARENT},
109         {SMB_VFS_OP(readahead_pread), SMB_VFS_OP_PREAD, SMB_VFS_LAYER_TRANSPARENT},
110         {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP}
111 };
112
113 NTSTATUS vfs_readahead_init(void);
114 NTSTATUS vfs_readahead_init(void)
115 {
116         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "readahead", readahead_ops);
117 }