Whamcloud - gitweb
Land b1_8_gate onto b1_8 (20081218_1708)
[fs/lustre-release.git] / lustre / llite / rw24.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * GPL HEADER START
5  *
6  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 only,
10  * as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License version 2 for more details (a copy is included
16  * in the LICENSE file that accompanied this code).
17  *
18  * You should have received a copy of the GNU General Public License
19  * version 2 along with this program; If not, see
20  * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
21  *
22  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
23  * CA 95054 USA or visit www.sun.com if you need additional information or
24  * have any questions.
25  *
26  * GPL HEADER END
27  */
28 /*
29  * Copyright  2008 Sun Microsystems, Inc. All rights reserved
30  * Use is subject to license terms.
31  */
32 /*
33  * This file is part of Lustre, http://www.lustre.org/
34  * Lustre is a trademark of Sun Microsystems, Inc.
35  *
36  * lustre/llite/rw24.c
37  *
38  * Lustre Lite I/O page cache for the 2.4 kernel version
39  */
40
41 #ifndef AUTOCONF_INCLUDED
42 #include <linux/config.h>
43 #endif
44 #include <linux/kernel.h>
45 #include <linux/mm.h>
46 #include <linux/string.h>
47 #include <linux/stat.h>
48 #include <linux/errno.h>
49 #include <linux/smp_lock.h>
50 #include <linux/unistd.h>
51 #include <linux/version.h>
52 #include <asm/system.h>
53 #include <asm/uaccess.h>
54
55 #include <linux/fs.h>
56 #include <linux/iobuf.h>
57 #include <linux/stat.h>
58 #include <asm/uaccess.h>
59 #include <linux/mm.h>
60 #include <linux/pagemap.h>
61 #include <linux/smp_lock.h>
62
63 #define DEBUG_SUBSYSTEM S_LLITE
64
65 #include <lustre_lite.h>
66 #include "llite_internal.h"
67 #include <linux/lustre_compat25.h>
68
69 static int ll_direct_IO_24(int rw,
70 #ifdef HAVE_DIO_FILE
71                            struct file *file,
72 #else
73                            struct inode *inode,
74 #endif
75                            struct kiobuf *iobuf, unsigned long blocknr,
76                            int blocksize)
77 {
78 #ifdef HAVE_DIO_FILE
79         struct inode *inode = file->f_dentry->d_inode;
80 #endif
81         struct ll_inode_info *lli = ll_i2info(inode);
82         struct lov_stripe_md *lsm = lli->lli_smd;
83         struct brw_page *pga;
84         struct obdo oa;
85         int length, i, flags, rc = 0;
86         loff_t offset, offset_orig;
87         ENTRY;
88
89         if (!lsm || !lsm->lsm_object_id)
90                 RETURN(-EBADF);
91
92         offset = ((obd_off)blocknr << inode->i_blkbits);
93         offset_orig = offset;
94         CDEBUG(D_VFSTRACE, "VFS Op:inode=%lu/%u(%p), size="LPSZ
95                ", offset=%lld=%llx, pages %u\n",
96                inode->i_ino, inode->i_generation, inode, iobuf->length,
97                offset, offset, iobuf->nr_pages);
98
99         /* FIXME: io smaller than CFS_PAGE_SIZE is broken on ia64 */
100         if ((iobuf->offset & (~CFS_PAGE_MASK)) ||
101             (iobuf->length & (~CFS_PAGE_MASK)))
102                 RETURN(-EINVAL);
103
104         OBD_ALLOC(pga, sizeof(*pga) * iobuf->nr_pages);
105         if (!pga)
106                 RETURN(-ENOMEM);
107
108         flags = 0 /* | OBD_BRW_DIRECTIO */;
109         length = iobuf->length;
110         rw = rw ? OBD_BRW_WRITE : OBD_BRW_READ;
111
112         for (i = 0, length = iobuf->length; length > 0;
113              length -= pga[i].count, offset += pga[i].count, i++) { /*i last!*/
114                 pga[i].pg = iobuf->maplist[i];
115                 pga[i].off = offset;
116                 /* To the end of the page, or the length, whatever is less */
117                 pga[i].count = min_t(int, CFS_PAGE_SIZE - (offset & ~CFS_PAGE_MASK),
118                                      length);
119                 pga[i].flag = flags;
120                 if (rw == OBD_BRW_READ)
121                         POISON_PAGE(iobuf->maplist[i], 0x0d);
122         }
123
124         ll_inode_fill_obdo(inode, rw, &oa);
125
126         if (rw == OBD_BRW_WRITE)
127                 ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_DIRECT_WRITE, iobuf->length);
128         else
129                 ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_DIRECT_READ, iobuf->length);
130         rc = obd_brw_rqset(rw, ll_i2obdexp(inode), &oa, lsm, iobuf->nr_pages,
131                            pga, NULL);
132         if ((rc > 0) && (rw == OBD_BRW_WRITE)) {
133                 lov_stripe_lock(lsm);
134                 obd_adjust_kms(ll_i2obdexp(inode), lsm, offset_orig + rc, 0);
135                 lov_stripe_unlock(lsm);
136         }
137
138         OBD_FREE(pga, sizeof(*pga) * iobuf->nr_pages);
139         RETURN(rc);
140 }
141
142 #ifdef KERNEL_HAS_AS_MAX_READAHEAD
143 static int ll_max_readahead(struct inode *inode)
144 {
145         return 0;
146 }
147 #endif
148
149 struct address_space_operations ll_aops = {
150         .readpage       = ll_readpage,
151         .direct_IO      = ll_direct_IO_24,
152         .writepage      = ll_writepage,
153         .prepare_write  = ll_prepare_write,
154         .commit_write   = ll_commit_write,
155         .removepage     = ll_removepage,
156         .sync_page      = NULL,
157         .bmap           = NULL,
158 #ifdef KERNEL_HAS_AS_MAX_READAHEAD
159         .max_readahead  = ll_max_readahead,
160 #endif
161 };