/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- * vim:expandtab:shiftwidth=8:tabstop=8: * * Lustre Lite I/O page cache for the 2.4 kernel version * * Copyright (c) 2001-2003 Cluster File Systems, Inc. * * This file is part of Lustre, http://www.lustre.org. * * Lustre is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public * License as published by the Free Software Foundation. * * Lustre 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 Lustre; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define DEBUG_SUBSYSTEM S_LLITE #include #include #include "llite_internal.h" #include #ifdef HAVE_DIO_FILE static int ll_direct_IO_24(int rw, struct file *file, struct kiobuf *iobuf, unsigned long blocknr, int blocksize) #else static int ll_direct_IO_24(int rw, struct inode *inode, struct kiobuf *iobuf, unsigned long blocknr, int blocksize) #endif { #ifdef HAVE_DIO_FILE struct inode *inode = file->f_dentry->d_inode; #endif struct ll_inode_info *lli = ll_i2info(inode); struct lov_stripe_md *lsm = lli->lli_smd; struct brw_page *pga; struct ptlrpc_request_set *set; struct obdo *oa = NULL; int length, i, flags, rc = 0; loff_t offset; ENTRY; if (!lsm || !lsm->lsm_object_id) RETURN(-EBADF); set = ptlrpc_prep_set(); if (set == NULL) RETURN(-ENOMEM); OBD_ALLOC(pga, sizeof(*pga) * iobuf->nr_pages); if (!pga) { ptlrpc_set_destroy(set); RETURN(-ENOMEM); } flags = 0 /* | OBD_BRW_DIRECTIO */; offset = ((obd_off)blocknr * blocksize); length = iobuf->length; pga[0].page_offset = iobuf->offset; LASSERT(iobuf->offset < PAGE_SIZE); for (i = 0, length = iobuf->length; length > 0; length -= pga[i].count, offset += pga[i].count, i++) { /*i last!*/ pga[i].pg = iobuf->maplist[i]; pga[i].disk_offset = offset; /* To the end of the page, or the length, whatever is less */ pga[i].count = min_t(int, PAGE_SIZE - pga[i].page_offset, length); pga[i].flag = flags; if (rw == READ) POISON_PAGE(iobuf->maplist[i], 0x0d); } oa = obdo_alloc(); if (oa == NULL) { ptlrpc_set_destroy(set); GOTO(out_free_pga, -ENOMEM); } ll_inode_fill_obdo(inode, rw, oa); if (rw == WRITE) lprocfs_counter_add(ll_i2sbi(inode)->ll_stats, LPROC_LL_DIRECT_WRITE, iobuf->length); else lprocfs_counter_add(ll_i2sbi(inode)->ll_stats, LPROC_LL_DIRECT_READ, iobuf->length); rc = obd_brw_async(rw == WRITE ? OBD_BRW_WRITE : OBD_BRW_READ, ll_i2dtexp(inode), oa, lsm, iobuf->nr_pages, pga, set, NULL); if (rc) { CDEBUG(rc == -ENOSPC ? D_INODE : D_ERROR, "error from obd_brw_async: rc = %d\n", rc); } else { rc = ptlrpc_set_wait(set); if (rc) CERROR("error from callback: rc = %d\n", rc); } ptlrpc_set_destroy(set); if (rc == 0 && rw == WRITE) { void lov_increase_kms(struct obd_export *, struct lov_stripe_md *, obd_off size); obd_off size = offset + length; lov_increase_kms(ll_i2dtexp(inode), lsm, size); if (size > inode->i_size) inode->i_size = size; } if (rc == 0) { rc = iobuf->length; obdo_to_inode(inode, oa, OBD_MD_FLBLOCKS); } obdo_free(oa); EXIT; out_free_pga: OBD_FREE(pga, sizeof(*pga) * iobuf->nr_pages); return rc; } struct address_space_operations ll_aops = { .readpage = ll_readpage, .direct_IO = ll_direct_IO_24, .writepage = ll_writepage, .prepare_write = ll_prepare_write, .commit_write = ll_commit_write, .removepage = ll_removepage, .sync_page = NULL, .bmap = NULL };