r22111: Allow readahead params to use size suffixes as K,M, etc.
[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 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 unsigned long get_offset_boundary(struct vfs_handle_struct *handle)
32 {
33         SMB_OFF_T off_bound = conv_str_size(lp_parm_const_string(SNUM(handle->conn),
34                                                 "readahead",
35                                                 "offset",
36                                                 NULL));
37         if (off_bound == 0) {
38                 off_bound = 0x80000;
39         }
40         return (unsigned long)off_bound;
41 }
42
43 static unsigned long get_offset_length(struct vfs_handle_struct *handle, unsigned long def_val)
44 {
45         SMB_OFF_T len = conv_str_size(lp_parm_const_string(SNUM(handle->conn),
46                                                 "readahead",
47                                                 "length",
48                                                 NULL));
49         if (len == 0) {
50                 len = def_val;
51         }
52         return (unsigned long)len;
53 }
54
55 static ssize_t readahead_sendfile(struct vfs_handle_struct *handle,
56                                         int tofd,
57                                         files_struct *fsp,
58                                         int fromfd,
59                                         const DATA_BLOB *header,
60                                         SMB_OFF_T offset,
61                                         size_t count)
62 {
63         unsigned long off_bound = get_offset_boundary(handle);
64         if ( offset % off_bound == 0) {
65                 unsigned long len = get_offset_length(handle, off_bound);
66 #if defined(HAVE_LINUX_READAHEAD)
67                 int err = readahead(fromfd, offset, (size_t)len);
68                 DEBUG(10,("readahead_sendfile: readahead on fd %u, offset %llu, len %u returned %d\n",
69                         (unsigned int)fromfd,
70                         (unsigned long long)offset,
71                         (unsigned int)len,
72                         err ));
73 #elif defined(HAVE_POSIX_FADVISE)
74                 int err = posix_fadvise(fromfd, offset, (off_t)len, POSIX_FADV_WILLNEED);
75                 DEBUG(10,("readahead_sendfile: posix_fadvise on fd %u, offset %llu, len %u returned %d\n",
76                         (unsigned int)fromfd,
77                         (unsigned long long)offset,
78                         (unsigned int)len,
79                         err ));
80 #else
81                 if (!didmsg) {
82                         DEBUG(0,("readahead_sendfile: no readahead on this platform\n"));
83                         didmsg = True;
84                 }
85 #endif
86         }
87         return SMB_VFS_NEXT_SENDFILE(handle,
88                                         tofd,
89                                         fsp,
90                                         fromfd,
91                                         header,
92                                         offset,
93                                         count);
94 }
95
96 static ssize_t readahead_pread(vfs_handle_struct *handle,
97                                 files_struct *fsp,
98                                 int fd,
99                                 void *data,
100                                 size_t count,
101                                 SMB_OFF_T offset)
102 {
103         unsigned long off_bound = get_offset_boundary(handle);
104         if ( offset % off_bound == 0) {
105                 unsigned long len = get_offset_length(handle, off_bound);
106 #if defined(HAVE_LINUX_READAHEAD)
107                 int err = readahead(fd, offset, (size_t)len);
108                 DEBUG(10,("readahead_pread: readahead on fd %u, offset %llu, len %u returned %d\n",
109                         (unsigned int)fd,
110                         (unsigned long long)offset,
111                         (unsigned int)len,
112                         err ));
113 #elif defined(HAVE_POSIX_FADVISE)
114                 int err = posix_fadvise(fromfd, offset, (off_t)len, POSIX_FADV_WILLNEED);
115                 DEBUG(10,("readahead_pread: posix_fadvise on fd %u, offset %llu, len %u returned %d\n",
116                         (unsigned int)fd,
117                         (unsigned long long)offset,
118                         (unsigned int)len,
119                         (err ));
120 #else
121                 if (!didmsg) {
122                         DEBUG(0,("readahead_pread: no readahead on this platform\n"));
123                         didmsg = True;
124                 }
125 #endif
126         }
127         return SMB_VFS_NEXT_PREAD(handle, fsp, fd, data, count, offset);
128 }
129
130 static vfs_op_tuple readahead_ops [] =
131 {
132         {SMB_VFS_OP(readahead_sendfile), SMB_VFS_OP_SENDFILE, SMB_VFS_LAYER_TRANSPARENT},
133         {SMB_VFS_OP(readahead_pread), SMB_VFS_OP_PREAD, SMB_VFS_LAYER_TRANSPARENT},
134         {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP}
135 };
136
137 NTSTATUS vfs_readahead_init(void);
138 NTSTATUS vfs_readahead_init(void)
139 {
140         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "readahead", readahead_ops);
141 }