root/source3/modules/vfs_cacheprime.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. prime_cache
  2. cprime_connect
  3. cprime_sendfile
  4. cprime_read
  5. cprime_pread
  6. vfs_cacheprime_init

   1 /*
   2  * Copyright (c) James Peach 2005-2006
   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 /* Cache priming module.
  21  *
  22  * The purpose of this module is to do RAID stripe width reads to prime the
  23  * buffer cache to do zero-copy I/O for subsequent sendfile calls. The idea is
  24  * to do a single large read at the start of the file to make sure that most or
  25  * all of the file is pulled into the buffer cache. Subsequent I/Os have
  26  * reduced latency.
  27  *
  28  * Tunables.
  29  *
  30  *      cacheprime:rsize    Amount of readahead in bytes. This should be a
  31  *                          multiple of the RAID stripe width.
  32  *      cacheprime:debug    Debug level at which to emit messages.
  33  */
  34 
  35 #define READAHEAD_MIN       (128 * 1024)        /* min is 128 KiB */
  36 #define READAHEAD_MAX       (100 * 1024 * 1024) /* max is 100 MiB */
  37 
  38 #define MODULE "cacheprime"
  39 
  40 static int module_debug;
  41 static ssize_t g_readsz = 0;
  42 static void * g_readbuf = NULL;
  43 
  44 /* Prime the kernel buffer cache with data from the specified file. We use
  45  * per-fsp data to make sure we only ever do this once. If pread is being
  46  * emulated by seek/read/seek, when this will suck quite a lot.
  47  */
  48 static bool prime_cache(
     /* [<][>][^][v][top][bottom][index][help] */
  49             struct vfs_handle_struct *  handle,
  50                         files_struct *                  fsp,
  51                         SMB_OFF_T                           offset,
  52                         size_t                              count)
  53 {
  54         SMB_OFF_T * last;
  55         ssize_t nread;
  56 
  57         last = (SMB_OFF_T *)VFS_ADD_FSP_EXTENSION(handle, fsp, SMB_OFF_T, NULL);
  58         if (!last) {
  59                 return False;
  60         }
  61 
  62         if (*last == -1) {
  63             /* Readahead disabled. */
  64             return False;
  65         }
  66 
  67         if ((*last + g_readsz) > (offset + count)) {
  68             /* Skip readahead ... we've already been here. */
  69             return False;
  70         }
  71 
  72         DEBUG(module_debug,
  73             ("%s: doing readahead of %lld bytes at %lld for %s\n",
  74             MODULE, (long long)g_readsz, (long long)*last,
  75             fsp->fsp_name));
  76 
  77         nread = sys_pread(fsp->fh->fd, g_readbuf, g_readsz, *last);
  78         if (nread < 0) {
  79             *last = -1;
  80             return False;
  81         }
  82 
  83         *last += nread;
  84         return True;
  85 }
  86 
  87 static int cprime_connect(
     /* [<][>][^][v][top][bottom][index][help] */
  88                 struct vfs_handle_struct *  handle,
  89                 const char *                service,
  90                 const char *                user)
  91 {
  92         module_debug = lp_parm_int(SNUM(handle->conn), MODULE, "debug", 100);
  93         if (g_readbuf) {
  94                 /* Only allocate g_readbuf once. If the config changes and
  95                  * another client multiplexes onto this smbd, we don't want
  96                  * to risk memory corruption.
  97                  */
  98                 return SMB_VFS_NEXT_CONNECT(handle, service, user);
  99         }
 100 
 101         g_readsz = conv_str_size(lp_parm_const_string(SNUM(handle->conn),
 102                                         MODULE, "rsize", NULL));
 103 
 104         if (g_readsz < READAHEAD_MIN) {
 105                 DEBUG(module_debug, ("%s: %ld bytes of readahead "
 106                             "requested, using minimum of %u\n",
 107                             MODULE, (long)g_readsz, READAHEAD_MIN));
 108                 g_readsz = READAHEAD_MIN;
 109         } else if (g_readsz > READAHEAD_MAX) {
 110                 DEBUG(module_debug, ("%s: %ld bytes of readahead "
 111                             "requested, using maximum of %u\n",
 112                             MODULE, (long)g_readsz, READAHEAD_MAX));
 113                 g_readsz = READAHEAD_MAX;
 114         }
 115 
 116         if ((g_readbuf = SMB_MALLOC(g_readsz)) == NULL) {
 117                 /* Turn off readahead if we can't get a buffer. */
 118                 g_readsz = 0;
 119         }
 120 
 121         return SMB_VFS_NEXT_CONNECT(handle, service, user);
 122 }
 123 
 124 static ssize_t cprime_sendfile(
     /* [<][>][^][v][top][bottom][index][help] */
 125                 struct vfs_handle_struct *  handle,
 126                 int                         tofd,
 127                 files_struct *              fromfsp,
 128                 const DATA_BLOB *           header,
 129                 SMB_OFF_T                   offset,
 130                 size_t                      count)
 131 {
 132         if (g_readbuf && offset == 0) {
 133                 prime_cache(handle, fromfsp, offset, count);
 134         }
 135 
 136         return SMB_VFS_NEXT_SENDFILE(handle, tofd, fromfsp,
 137                                      header, offset, count);
 138 }
 139 
 140 static ssize_t cprime_read(
     /* [<][>][^][v][top][bottom][index][help] */
 141                 vfs_handle_struct * handle,
 142                 files_struct *      fsp,
 143                 void *              data,
 144                 size_t              count)
 145 {
 146         SMB_OFF_T offset;
 147 
 148         offset = SMB_VFS_LSEEK(fsp, 0, SEEK_CUR);
 149         if (offset >= 0 && g_readbuf)  {
 150                 prime_cache(handle, fsp, offset, count);
 151                 SMB_VFS_LSEEK(fsp, offset, SEEK_SET);
 152         }
 153 
 154         return SMB_VFS_NEXT_READ(handle, fsp, data, count);
 155 }
 156 
 157 static ssize_t cprime_pread(
     /* [<][>][^][v][top][bottom][index][help] */
 158                 vfs_handle_struct * handle,
 159                 files_struct *      fsp,
 160                 void *              data,
 161                         size_t              count,
 162                 SMB_OFF_T           offset)
 163 {
 164         if (g_readbuf) {
 165                 prime_cache(handle, fsp, offset, count);
 166         }
 167 
 168         return SMB_VFS_NEXT_PREAD(handle, fsp, data, count, offset);
 169 }
 170 
 171 static vfs_op_tuple cprime_ops [] =
 172 {
 173         {SMB_VFS_OP(cprime_sendfile),
 174                 SMB_VFS_OP_SENDFILE, SMB_VFS_LAYER_TRANSPARENT},
 175         {SMB_VFS_OP(cprime_pread),
 176                 SMB_VFS_OP_PREAD, SMB_VFS_LAYER_TRANSPARENT},
 177         {SMB_VFS_OP(cprime_read),
 178                 SMB_VFS_OP_READ, SMB_VFS_LAYER_TRANSPARENT},
 179         {SMB_VFS_OP(cprime_connect),
 180                 SMB_VFS_OP_CONNECT,  SMB_VFS_LAYER_TRANSPARENT},
 181 
 182         {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP}
 183 };
 184 
 185 /* -------------------------------------------------------------------------
 186  * Samba module initialisation entry point.
 187  * -------------------------------------------------------------------------
 188  */
 189 
 190 NTSTATUS vfs_cacheprime_init(void);
 191 NTSTATUS vfs_cacheprime_init(void)
     /* [<][>][^][v][top][bottom][index][help] */
 192 {
 193     return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, MODULE, cprime_ops);
 194 }
 195 
 196 /* vim: set sw=4 ts=4 tw=79 et: */

/* [<][>][^][v][top][bottom][index][help] */