modules/vfs_prealloc.c

説明を見る。
00001 /*
00002  * XFS preallocation support module.
00003  *
00004  * Copyright (c) James Peach 2006
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00019  */
00020 
00021 #include "includes.h"
00022 
00023 /* Extent preallocation module.
00024  *
00025  * The purpose of this module is to preallocate space on the filesystem when
00026  * we have a good idea of how large files are supposed to be. This lets writes
00027  * proceed without having to allocate new extents and results in better file
00028  * layouts on disk.
00029  *
00030  * Currently only implemented for XFS. This module is based on an original idea
00031  * and implementation by Sebastian Brings.
00032  *
00033  * Tunables.
00034  *
00035  *      prealloc: <ext>     Number of bytes to preallocate for a file with
00036  *                          the matching extension.
00037  *      prealloc:debug      Debug level at which to emit messages.
00038  *
00039  * Example.
00040  *
00041  *      prealloc:mpeg = 500M  # Preallocate *.mpeg to 500 MiB.
00042  */
00043 
00044 #ifdef HAVE_XFS_LIBXFS_H
00045 #include <xfs/libxfs.h>
00046 #define lock_type xfs_flock64_t
00047 #else
00048 #define lock_type struct flock64
00049 #endif
00050 
00051 #define MODULE "prealloc"
00052 static int module_debug;
00053 
00054 static int preallocate_space(int fd, SMB_OFF_T size)
00055 {
00056         lock_type fl = {0};
00057         int err;
00058 
00059         if (size <= 0) {
00060                 return 0;
00061         }
00062 
00063         fl.l_whence = SEEK_SET;
00064         fl.l_start = 0;
00065         fl.l_len = size;
00066 
00067         /* IMPORTANT: We use RESVSP because we want the extents to be
00068          * allocated, but we don't want the allocation to show up in
00069          * st_size or persist after the close(2).
00070          */
00071 
00072 #if defined(XFS_IOC_RESVSP64)
00073         /* On Linux this comes in via libxfs.h. */
00074         err = xfsctl(NULL, fd, XFS_IOC_RESVSP64, &fl);
00075 #elif defined(F_RESVSP64)
00076         /* On IRIX, this comes from fcntl.h. */
00077         err = fcntl(fd, F_RESVSP64, &fl);
00078 #else
00079         err = -1;
00080         errno = ENOSYS;
00081 #endif
00082 
00083         if (err) {
00084                 DEBUG(module_debug,
00085                         ("%s: preallocate failed on fd=%d size=%lld: %s\n",
00086                         MODULE, fd, (long long)size, strerror(errno)));
00087         }
00088 
00089         return err;
00090 }
00091 
00092 static int prealloc_connect(
00093                 struct vfs_handle_struct *  handle,
00094                 const char *                service,
00095                 const char *                user)
00096 {
00097             module_debug = lp_parm_int(SNUM(handle->conn),
00098                                         MODULE, "debug", 100);
00099 
00100             return SMB_VFS_NEXT_CONNECT(handle, service, user);
00101 }
00102 
00103 static int prealloc_open(vfs_handle_struct* handle,
00104                         const char *        fname,
00105                         files_struct *      fsp,
00106                         int                 flags,
00107                         mode_t              mode)
00108 {
00109         int fd;
00110         off64_t size = 0;
00111 
00112         const char * dot;
00113         char fext[10];
00114 
00115         if (!(flags & (O_CREAT|O_TRUNC))) {
00116                 /* Caller is not intending to rewrite the file. Let's not mess
00117                  * with the allocation in this case.
00118                  */
00119                 goto normal_open;
00120         }
00121 
00122         *fext = '\0';
00123         dot = strrchr(fname, '.');
00124         if (dot && *++dot) {
00125                 if (strlen(dot) < sizeof(fext)) {
00126                         strncpy(fext, dot, sizeof(fext));
00127                         strnorm(fext, CASE_LOWER);
00128                 }
00129         }
00130 
00131         if (*fext == '\0') {
00132                 goto normal_open;
00133         }
00134 
00135         /* Syntax for specifying preallocation size is:
00136          *      MODULE: <extension> = <size>
00137          * where
00138          *      <extension> is the file extension in lower case
00139          *      <size> is a size like 10, 10K, 10M
00140          */
00141         size = conv_str_size(lp_parm_const_string(SNUM(handle->conn), MODULE,
00142                                                     fext, NULL));
00143         if (size <= 0) {
00144                 /* No need to preallocate this file. */
00145                 goto normal_open;
00146         }
00147 
00148         fd = SMB_VFS_NEXT_OPEN(handle, fname, fsp, flags, mode);
00149         if (fd < 0) {
00150                 return fd;
00151         }
00152 
00153         /* Prellocate only if the file is being created or replaced. Note that
00154          * Samba won't ever pass down O_TRUNC, which is why we have to handle
00155          * truncate calls specially.
00156          */
00157         if ((flags & O_CREAT) || (flags & O_TRUNC)) {
00158                 SMB_OFF_T * psize;
00159 
00160                 psize = VFS_ADD_FSP_EXTENSION(handle, fsp, SMB_OFF_T);
00161                 if (psize == NULL || *psize == -1) {
00162                         return fd;
00163                 }
00164 
00165                 DEBUG(module_debug,
00166                         ("%s: preallocating %s (fd=%d) to %lld bytes\n",
00167                         MODULE, fname, fd, (long long)size));
00168 
00169                 *psize = size;
00170                 if (preallocate_space(fd, *psize) < 0) {
00171                         VFS_REMOVE_FSP_EXTENSION(handle, fsp);
00172                 }
00173         }
00174 
00175         return fd;
00176 
00177 normal_open:
00178         /* We are not creating or replacing a file. Skip the
00179          * preallocation.
00180          */
00181         DEBUG(module_debug, ("%s: skipping preallocation for %s\n",
00182                     MODULE, fname));
00183         return SMB_VFS_NEXT_OPEN(handle, fname, fsp, flags, mode);
00184 }
00185 
00186 static int prealloc_ftruncate(vfs_handle_struct * handle,
00187                         files_struct *  fsp,
00188                         int             fd,
00189                         SMB_OFF_T       offset)
00190 {
00191         SMB_OFF_T *psize;
00192         int ret = SMB_VFS_NEXT_FTRUNCATE(handle, fsp, fd, offset);
00193 
00194         /* Maintain the allocated space even in the face of truncates. */
00195         if ((psize = VFS_FETCH_FSP_EXTENSION(handle, fsp))) {
00196                 preallocate_space(fd, *psize);
00197         }
00198 
00199         return ret;
00200 }
00201 
00202 static vfs_op_tuple prealloc_op_tuples[] = {
00203         {SMB_VFS_OP(prealloc_open), SMB_VFS_OP_OPEN, SMB_VFS_LAYER_TRANSPARENT},
00204         {SMB_VFS_OP(prealloc_ftruncate), SMB_VFS_OP_FTRUNCATE, SMB_VFS_LAYER_TRANSPARENT},
00205         {SMB_VFS_OP(prealloc_connect), SMB_VFS_OP_CONNECT, SMB_VFS_LAYER_TRANSPARENT},
00206         {NULL,  SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP}
00207 };
00208 
00209 NTSTATUS vfs_prealloc_init(void);
00210 NTSTATUS vfs_prealloc_init(void)
00211 {
00212         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
00213                 MODULE, prealloc_op_tuples);
00214 }
00215 

Sambaに対してSat Aug 29 21:23:07 2009に生成されました。  doxygen 1.4.7