/* * Copyright (c) 2009 Simon Wilkinson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* Linux specific store operations * * The idea of these operations is to reduce the number of copies * that data incurs when passing from the disk cache through to the * RX layer, and vice versa. * * In kernels which support it, we use the splice() operation - in * older kernels, the filesystem's sendpage() operation is used directly. * Either way, this means that we can get direct access to the page contents, * rather than getting a copy. */ #include #include "afs/param.h" #include #if 0 && defined(HAVE_LINUX_SPLICE_DIRECT_TO_ACTOR) # include #else # include #endif #include "afs/sysincludes.h" #include "afsincludes.h" #if 0 && defined(HAVE_LINUX_SPLICE_DIRECT_TO_ACTOR) static int afs_linux_splice_actor(struct pipe_inode_info *pipe, struct pipe_buffer *buf, struct splice_desc *sd) { struct rxfs_storeVariables *svar = sd->u.data; size_t size; int code; code = buf->ops->confirm(pipe, buf); if (code) return code; size = sd->len; /* Eventually, this could be rx_WritePage */ code = rx_Write(svar->call, kmap(buf->page), size); if (code != size) size = -33; /* Can't get a proper rx error out from here */ kunmap(buf->page); return size; } static int afs_linux_ds_actor(struct pipe_inode_info *pipe, struct splice_desc *sd) { return __splice_from_pipe(pipe, sd, afs_linux_splice_actor); } /* This is a store proc which uses splice to reduce the number * of page copies. */ afs_int32 afs_linux_storeproc(struct storeOps *ops, void *rock, struct dcache *tdc, int *shouldwake, afs_size_t *bytesXferred) { struct rxfs_storeVariables *svar = rock; struct file *cacheFp; struct splice_desc sd = { .len = 0, .total_len = tdc->f.chunkBytes, .pos = 0, .u.data = rock }; int code; /* Open the file, splice its contents */ AFS_GUNLOCK(); cacheFp = afs_linux_raw_open(&tdc->f.inode); code = splice_direct_to_actor(cacheFp, &sd, afs_linux_ds_actor); filp_close(cacheFp, NULL); AFS_GLOCK(); /* If we're being called from a backing request, then wake up that * request once the file server says its happy. Potentially, we should * do this each time we rx_Write, but that would mean acquiring the * GLOCK in the middle of our actor */ if (shouldwake && *shouldwake && ((*ops->status)(rock) == 0)) { *shouldwake = 0; afs_wakeup(svar->vcache); } if (code > 0) { *bytesXferred+=code; return 0; } return code; } # else static int afs_linux_read_actor(read_descriptor_t *desc, struct page *page, unsigned long offset, unsigned long size) { #ifdef READ_DESCRIPTOR_T_HAS_BUF struct rxfs_storeVariables *svar = (void *) desc->buf; #else struct rxfs_storeVariables *svar = desc->arg.data; #endif unsigned long count = desc->count; int code; if (size > count) size = count; /* Eventually, this could be rx_WritePage */ code = rx_Write(svar->call, kmap(page) + offset, size); kunmap(page); if (code != size) { return -33; /* Can't get a proper rx error out from here */ } desc->count = count - size; desc->written += size; return size; } #if 0 afs_int32 afs_linux_storeproc(struct storeOps *ops, void *rock, struct dcache *tdc, int *shouldwake, afs_size_t *bytesXferred) { struct rxfs_storeVariables *svar = rock; struct file *cacheFp; int code; loff_t offset = 0; /* Open the file, splice its contents */ AFS_GUNLOCK(); cacheFp = afs_linux_raw_open(&tdc->f.inode); code = cacheFp->f_op->sendfile(cacheFp, &offset, tdc->f.chunkBytes, afs_linux_read_actor, rock); filp_close(cacheFp, NULL); AFS_GLOCK(); /* If we're being called from a backing request, then wake up that * request once the file server says its happy. Potentially, we should * do this each time we rx_Write, but that would mean acquiring the * GLOCK in the middle of our actor */ if (shouldwake && *shouldwake && ((*ops->status)(rock) == 0)) { *shouldwake = 0; afs_wakeup(svar->vcache); } if (code > 0) { *bytesXferred+=code; return 0; } return code; } #endif #endif