From ae9f3f3d41f25618e2e1f0b206c4c4032bdf1509 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 21 Jan 2011 14:07:15 +0100 Subject: [PATCH] v3-6-ctdb: s3:vfs: Add a gpfs_prefetch module. This can not go upstream yet because it uses the gpfs_fcntl call from the non-GPL libgpfs. --- source3/Makefile.in | 5 + source3/configure.in | 2 + source3/modules/vfs_gpfs_prefetch.c | 309 ++++++++++++++++++++++++++++ 3 files changed, 316 insertions(+) create mode 100644 source3/modules/vfs_gpfs_prefetch.c diff --git a/source3/Makefile.in b/source3/Makefile.in index c5ec5891c9..55f0141ccc 100644 --- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -824,6 +824,7 @@ VFS_PREALLOC_OBJ = modules/vfs_prealloc.o VFS_COMMIT_OBJ = modules/vfs_commit.o VFS_GPFS_OBJ = modules/vfs_gpfs.o modules/gpfs.o modules/nfs4_acls.o VFS_GPFS_HSM_NOTIFY_OBJ = modules/vfs_gpfs_hsm_notify.o +VFS_GPFS_PREFETCH_OBJ = modules/vfs_gpfs_prefetch.o modules/gpfs.o VFS_NOTIFY_FAM_OBJ = modules/vfs_notify_fam.o VFS_READAHEAD_OBJ = modules/vfs_readahead.o VFS_TSMSM_OBJ = modules/vfs_tsmsm.o @@ -3011,6 +3012,10 @@ bin/gpfs_hsm_notify.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_GPFS_HSM_NOTIFY_OBJ) @echo "Building plugin $@" @$(SHLD_MODULE) $(VFS_GPFS_HSM_NOTIFY_OBJ) +bin/gpfs_prefetch.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_GPFS_PREFETCH_OBJ) + @echo "Building plugin $@" + @$(SHLD_MODULE) $(VFS_GPFS_PREFETCH_OBJ) + bin/notify_fam.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_NOTIFY_FAM_OBJ) @echo "Building plugin $@" @$(SHLD_MODULE) $(VFS_NOTIFY_FAM_OBJ) @SMB_FAM_LIBS@ diff --git a/source3/configure.in b/source3/configure.in index 9b49c96c60..f888497912 100644 --- a/source3/configure.in +++ b/source3/configure.in @@ -1128,6 +1128,7 @@ if test x"$ac_cv_header_gpfs_gpl_h" = x"yes"; then AC_DEFINE(HAVE_GPFS,1,[Whether GPFS GPL headers are available]) default_shared_modules="$default_shared_modules vfs_gpfs" default_shared_modules="$default_shared_modules vfs_gpfs_hsm_notify" + default_shared_modules="$default_shared_modules vfs_gpfs_prefetch" fi ############################################# @@ -6895,6 +6896,7 @@ SMB_MODULE(vfs_prealloc, \$(VFS_PREALLOC_OBJ), "bin/prealloc.$SHLIBEXT", VFS) SMB_MODULE(vfs_commit, \$(VFS_COMMIT_OBJ), "bin/commit.$SHLIBEXT", VFS) SMB_MODULE(vfs_gpfs, \$(VFS_GPFS_OBJ), "bin/gpfs.$SHLIBEXT", VFS) SMB_MODULE(vfs_gpfs_hsm_notify, \$(VFS_GPFS_PREFETCH_OBJ), "bin/gpfs_hsm_notify.$SHLIBEXT", VFS) +SMB_MODULE(vfs_gpfs_prefetch, \$(VFS_GPFS_PREFETCH_OBJ), "bin/gpfs_prefetch.$SHLIBEXT", VFS) SMB_MODULE(vfs_readahead, \$(VFS_READAHEAD_OBJ), "bin/readahead.$SHLIBEXT", VFS) SMB_MODULE(vfs_tsmsm, \$(VFS_TSMSM_OBJ), "bin/tsmsm.$SHLIBEXT", VFS) SMB_MODULE(vfs_fileid, \$(VFS_FILEID_OBJ), "bin/fileid.$SHLIBEXT", VFS) diff --git a/source3/modules/vfs_gpfs_prefetch.c b/source3/modules/vfs_gpfs_prefetch.c new file mode 100644 index 0000000000..9d79b2095b --- /dev/null +++ b/source3/modules/vfs_gpfs_prefetch.c @@ -0,0 +1,309 @@ +/* + Unix SMB/CIFS implementation. + Make use of gpfs prefetch functionality + + Copyright (C) Volker Lendecke 2008 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#include "includes.h" +#include "smbd/proto.h" +#include "include/smbprofile.h" + +#undef DBGC_CLASS +#define DBGC_CLASS DBGC_VFS + +#include +#include + +static int (*gpfs_fcntl_fn)(int fd, void *arg); + +static int smbd_gpfs_fcntl(int fd, void *arg) +{ + static void *libgpfs_handle = NULL; + + DEBUG(10, ("smbd_gpfs_fcntl called for %d\n", fd)); + + if (gpfs_fcntl_fn == NULL) { + libgpfs_handle = dlopen("libgpfs.so", RTLD_LAZY); + + if (libgpfs_handle == NULL) { + DEBUG(10, ("sys_dlopen for libgpfs failed: %s\n", + strerror(errno))); + return -1; + } + + gpfs_fcntl_fn = dlsym(libgpfs_handle, "gpfs_fcntl"); + if (gpfs_fcntl_fn == NULL) { + DEBUG(3, ("libgpfs.so does not contain the symbol " + "'gpfs_fcntl'\n")); + errno = ENOSYS; + return -1; + } + } + + return gpfs_fcntl_fn(fd, arg); +} + +struct gpfs_prefetch_config { + name_compare_entry *namelist; + size_t size; +}; + +struct gpfs_prefetch_hints { + blksize_t st_blksize; + /* + * The current center around which config->size bytes are + * prefetched + */ + SMB_OFF_T center; +}; + +static void gpfs_prefetch_recenter(vfs_handle_struct *handle, + files_struct *fsp, + SMB_OFF_T offset, size_t size, + struct gpfs_prefetch_hints *hints) +{ + int ret; + SMB_OFF_T new_center; + + struct { + gpfsFcntlHeader_t hdr; + gpfsMultipleAccessRange_t acc; + } arg; + + + if (hints->st_blksize == 0) { + SMB_STRUCT_STAT sbuf; + + if (SMB_VFS_NEXT_FSTAT(handle, fsp, &sbuf) == -1) { + return; + } + DEBUG(10, ("gpfs_prefetch_recenter: st_blksize = %d\n", + (int)sbuf.st_ex_blksize)); + hints->st_blksize = sbuf.st_ex_blksize; + } + + new_center = (offset > size) ? offset : 0; + + DEBUG(10, ("gpfs_prefetch_recenter: size=%d, offset=%d, " + "old_center=%d, new_center=%d\n", (int)size, (int)offset, + (int)hints->center, (int)new_center)); + + ZERO_STRUCT(arg); + + arg.hdr.totalLength = sizeof(arg); + arg.hdr.fcntlVersion = GPFS_FCNTL_CURRENT_VERSION; + arg.hdr.fcntlReserved = 0; + arg.acc.structLen = sizeof(arg.acc); + arg.acc.structType = GPFS_MULTIPLE_ACCESS_RANGE; + arg.acc.accRangeCnt = 1; + arg.acc.relRangeCnt = 1; + + arg.acc.accRangeArray[0].blockNumber = new_center/hints->st_blksize; + arg.acc.accRangeArray[0].start = 0; + arg.acc.accRangeArray[0].length = size; + arg.acc.accRangeArray[0].isWrite = 0; + + arg.acc.relRangeArray[0].blockNumber = hints->center/hints->st_blksize; + arg.acc.relRangeArray[0].start = 0; + arg.acc.relRangeArray[0].length = size; + arg.acc.relRangeArray[0].isWrite = 0; + + ret = smbd_gpfs_fcntl(fsp->fh->fd, &arg); + if (ret == -1) { + DEBUG(5, ("gpfs_fcntl returned %s\n", strerror(errno))); + } + + hints->center = new_center; +} + +static ssize_t gpfs_prefetch_pread(vfs_handle_struct *handle, + files_struct *fsp, void *data, + size_t n, SMB_OFF_T offset) +{ + struct gpfs_prefetch_config *config = + (struct gpfs_prefetch_config *)handle->data; + struct gpfs_prefetch_hints *hints = (struct gpfs_prefetch_hints *) + VFS_FETCH_FSP_EXTENSION(handle, fsp); + SMB_OFF_T out_of_center; + + /* + * How far away from the center of the prefetch region is the + * request? + */ + + out_of_center = (offset > hints->center) + ? (offset - hints->center) : (hints->center - offset); + + DEBUG(10, ("gpfs_prefetch_pread: n=%d, offset=%d, center=%d, " + "out_of_center=%d, size=%d\n", (int)n, (int)offset, + (int)hints->center, (int)out_of_center, + (int)config->size)); + /* + * Are we completely out of the prefetch range or less than + * 10% at its borders? + */ + + if ((out_of_center > config->size) + || ((config->size - out_of_center) * 10 < config->size)) { + /* + * Re-center the prefetch area + */ + gpfs_prefetch_recenter(handle, fsp, offset, config->size, + hints); + } + + return SMB_VFS_NEXT_PREAD(handle, fsp, data, n, offset); +} + +static int gpfs_prefetch_open(struct vfs_handle_struct *handle, + struct smb_filename *smb_fname, + files_struct *fsp, + int flags, mode_t mode) +{ + int fd, ret; + struct gpfs_prefetch_hints *hints; + struct gpfs_prefetch_config *config = + (struct gpfs_prefetch_config *)handle->data; + + struct { + gpfsFcntlHeader_t hdr; + gpfsAccessRange_t acc; + } arg; + + DEBUG(10, ("gpfs_prefetch_open called for %s, config=%p, " + "config->namelist = %p, config->size=%d\n", + smb_fname->base_name, + config, config->namelist, (int)config->size)); + + if (!is_in_path(smb_fname->base_name, config->namelist, + handle->conn->case_sensitive)) { + DEBUG(10, ("gpfs_prefetch_open not in list: %s\n", + smb_fname->base_name)); + return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, + mode); + } + + hints = (struct gpfs_prefetch_hints *)VFS_ADD_FSP_EXTENSION( + handle, fsp, struct gpfs_prefetch_hints, NULL); + if (hints == NULL) { + errno = ENOMEM; + return -1; + } + + fd = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode); + if (fd == -1) { + VFS_REMOVE_FSP_EXTENSION(handle, fsp); + return -1; + } + + arg.hdr.totalLength = sizeof(arg); + arg.hdr.fcntlVersion = GPFS_FCNTL_CURRENT_VERSION; + arg.hdr.fcntlReserved = 0; + arg.acc.structLen = sizeof(arg.acc); + arg.acc.structType = GPFS_ACCESS_RANGE; + arg.acc.start = 0; + arg.acc.length = 1; + arg.acc.isWrite = 0; + + ret = smbd_gpfs_fcntl(fd, &arg); + if (ret == -1) { + DEBUG(5, ("gpfs_fcntl returned %s\n", strerror(errno))); + } + + hints->st_blksize = 0; + hints->center = 0; + + return fd; +} + +static void gpfs_prefetch_config_free(void **data) +{ + struct gpfs_prefetch_config **config = + (struct gpfs_prefetch_config **)data; + + free_namearray((*config)->namelist); + TALLOC_FREE(*config); +} + +static int gpfs_prefetch_connect(struct vfs_handle_struct *handle, + const char *service, + const char *user) +{ + struct gpfs_prefetch_config *config; + const char *mask; + + config = talloc(handle, struct gpfs_prefetch_config); + if (config == NULL) { + DEBUG(0, ("talloc failed\n")); + errno = ENOMEM; + return -1; + } + + mask = lp_parm_const_string(SNUM(handle->conn), "gpfs_prefetch", + "mask", ""); + + set_namearray(&config->namelist, mask); + config->size = lp_parm_int(SNUM(handle->conn), "gpfs_prefetch", + "size", 1024); + + /* + * The size calculations in the core routines assume that + * config->size is the size from the center to the border of + * the prefetched area. So we need to multiply by 1024/2 here + * to get the whole prefetch area in kilobytes. + */ + config->size *= 1024/2; + + SMB_VFS_HANDLE_SET_DATA(handle, config, gpfs_prefetch_config_free, + struct gpfs_prefetch_config, goto fail); + + return SMB_VFS_NEXT_CONNECT(handle, service, user); + +fail: + free_namearray(config->namelist); + TALLOC_FREE(config); + return -1; +} + +/* VFS operations structure */ + +static struct vfs_fn_pointers gpfs_prefetch_fns = { + .open_fn = gpfs_prefetch_open, + .pread = gpfs_prefetch_pread, + .connect_fn = gpfs_prefetch_connect, +}; + +/* + * When done properly upstream (GPL issue resolved), change this + * routine name to vfs_gpfs_prefetch_init!! + */ + +NTSTATUS init_samba_module(void); +NTSTATUS init_samba_module(void) +{ + NTSTATUS status; + + DEBUG(10, ("vfs_gpfs_prefetch_init called\n")); + + status = smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "gpfs_prefetch", + &gpfs_prefetch_fns); + DEBUG(10, ("smb_register_vfs returned %s\n", + nt_errstr(status))); + + return status; +} -- 2.34.1