Whamcloud - gitweb
Part of the O_DIRECT fix. The page indices iobuf->maplist[i]->index
[fs/lustre-release.git] / lustre / llite / rw.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * Lustre Lite I/O Page Cache
5  *
6  * Copyright (C) 2002 Cluster File Systems, Inc. 
7  */
8
9 #include <linux/config.h>
10 #include <linux/kernel.h>
11 #include <linux/mm.h>
12 #include <linux/string.h>
13 #include <linux/stat.h>
14 #include <linux/iobuf.h>
15 #include <linux/errno.h>
16 #include <linux/locks.h>
17 #include <linux/unistd.h>
18 #include <linux/version.h>
19 #include <asm/system.h>
20 #include <asm/uaccess.h>
21
22 #include <linux/fs.h>
23 #include <linux/stat.h>
24 #include <asm/uaccess.h>
25 #include <asm/segment.h>
26 #include <linux/mm.h>
27 #include <linux/pagemap.h>
28 #include <linux/smp_lock.h>
29
30 #define DEBUG_SUBSYSTEM S_LLITE
31
32 #include <linux/lustre_mds.h>
33 #include <linux/lustre_lite.h>
34 #include <linux/lustre_lib.h>
35
36 inline struct obdo * ll_oa_from_inode(struct inode *inode, unsigned long valid)
37 {
38         struct ll_inode_info *oinfo = ll_i2info(inode);
39         struct obdo *oa = obdo_alloc();
40         if ( !oa ) {
41                 CERROR("no memory to allocate obdo!\n"); 
42                 return NULL;
43         }
44         oa->o_valid = valid;
45
46         if ( valid & OBD_MD_FLID )
47                 oa->o_id = oinfo->lli_objid;
48         if ( valid & OBD_MD_FLATIME )
49                 oa->o_atime = inode->i_atime;
50         if ( valid & OBD_MD_FLMTIME )
51                 oa->o_mtime = inode->i_mtime;
52         if ( valid & OBD_MD_FLCTIME )
53                 oa->o_ctime = inode->i_ctime;
54         if ( valid & OBD_MD_FLSIZE )
55                 oa->o_size = inode->i_size;
56         if ( valid & OBD_MD_FLBLOCKS )   /* allocation of space */
57                 oa->o_blocks = inode->i_blocks;
58         if ( valid & OBD_MD_FLBLKSZ )
59                 oa->o_blksize = inode->i_blksize;
60         if ( valid & OBD_MD_FLMODE )
61                 oa->o_mode = inode->i_mode;
62         if ( valid & OBD_MD_FLUID )
63                 oa->o_uid = inode->i_uid;
64         if ( valid & OBD_MD_FLGID )
65                 oa->o_gid = inode->i_gid;
66         if ( valid & OBD_MD_FLFLAGS )
67                 oa->o_flags = inode->i_flags;
68         if ( valid & OBD_MD_FLNLINK )
69                 oa->o_nlink = inode->i_nlink;
70         if ( valid & OBD_MD_FLGENER ) 
71                 oa->o_generation = inode->i_generation;
72
73         CDEBUG(D_INFO, "src inode %ld, dst obdo %ld valid 0x%08lx\n",
74                inode->i_ino, (long)oa->o_id, valid);
75 #if 0
76         /* this will transfer metadata for the logical object to 
77            the oa: that metadata could contain the constituent objects
78         */
79         if (ll_has_inline(inode)) {
80                 CDEBUG(D_INODE, "copying inline data from inode to obdo\n");
81                 memcpy(oa->o_inline, oinfo->lli_inline, OBD_INLINESZ);
82                 oa->o_obdflags |= OBD_FL_INLINEDATA;
83                 oa->o_valid |= OBD_MD_FLINLINE;
84         }
85 #endif
86         return oa;
87 } /* ll_oa_from_inode */
88
89 /* SYNCHRONOUS I/O to object storage for an inode */
90 static int ll_brw(int rw, struct inode *inode, struct page *page, int create)
91 {
92         obd_count        num_obdo = 1;
93         obd_count        bufs_per_obdo = 1;
94         struct obdo     *oa;
95         obd_size         count = PAGE_SIZE;
96         obd_off          offset = ((obd_off)page->index) << PAGE_SHIFT;
97         obd_flag         flags = create ? OBD_BRW_CREATE : 0;
98         int              err;
99         ENTRY;
100
101         oa = ll_oa_from_inode(inode, OBD_MD_FLNOTOBD);
102         if (!oa)
103                 RETURN(-ENOMEM);
104
105         err = obd_brw(rw, ll_i2obdconn(inode), num_obdo, &oa, &bufs_per_obdo,
106                       &page, &count, &offset, &flags);
107
108         obdo_free(oa);
109         RETURN(err);
110 } /* ll_brw */
111
112 /* returns the page unlocked, but with a reference */
113 static int ll_readpage(struct file *file, struct page *page)
114 {
115         struct inode *inode = page->mapping->host;
116         int rc = 0;
117         ENTRY;
118
119         if (!PageLocked(page))
120                 LBUG();
121
122         if (((inode->i_size + PAGE_CACHE_SIZE -1)>>PAGE_SHIFT) <= page->index) {
123                 memset(kmap(page), 0, PAGE_CACHE_SIZE);
124                 kunmap(page);
125                 GOTO(readpage_out, rc);
126         }
127
128         if (Page_Uptodate(page)) {
129                 CERROR("Explain this please?\n");
130                 GOTO(readpage_out, rc);
131         }
132
133         rc = ll_brw(OBD_BRW_READ, inode, page, 0);
134         EXIT;
135
136  readpage_out:
137         if (!rc)
138                 SetPageUptodate(page);
139         UnlockPage(page);
140         return 0;
141 } /* ll_readpage */
142
143
144 static int ll_prepare_write(struct file *file, struct page *page, unsigned from,
145                             unsigned to)
146 {
147         struct inode *inode = page->mapping->host;
148         obd_off offset = ((obd_off)page->index) << PAGE_SHIFT;
149         int rc = 0;
150         char *addr;
151         ENTRY; 
152         
153         addr = kmap(page);
154         if (!PageLocked(page))
155                 LBUG();
156
157         if (Page_Uptodate(page))
158                 GOTO(prepare_done, rc);
159
160         if (offset + from >= inode->i_size) {
161                 memset(addr, 0, PAGE_SIZE);
162                 GOTO(prepare_done, rc);
163         }
164
165         /* We're completely overwriting an existing page, so _don't_ set it up
166          * to date until commit_write */
167         if (from == 0 && to == PAGE_SIZE) {
168                 memset(addr, 0, PAGE_SIZE);
169                 RETURN(0);
170         }
171
172         rc = ll_brw(OBD_BRW_READ, inode, page, 0);
173
174         EXIT;
175  prepare_done:
176         if (!rc)
177                 SetPageUptodate(page);
178
179         return rc;
180 }
181
182 /* returns the page unlocked, but with a reference */
183 static int ll_writepage(struct page *page)
184 {
185         struct inode *inode = page->mapping->host;
186         int err;
187         ENTRY;
188
189         if (!PageLocked(page))
190                 LBUG();
191
192         err = ll_brw(OBD_BRW_WRITE, inode, page, 1);
193         if ( !err ) {
194                 //SetPageUptodate(page);
195                 set_page_clean(page);
196         } else {
197                 CERROR("ll_brw failure %d\n", err);
198         }
199         UnlockPage(page); 
200         RETURN(err);
201 }
202
203 /* SYNCHRONOUS I/O to object storage for an inode -- object attr will be updated
204  * too */
205 static int ll_commit_write(struct file *file, struct page *page,
206                            unsigned from, unsigned to)
207 {
208         int create = 1;
209         struct inode *inode = page->mapping->host;
210         obd_count        num_obdo = 1;
211         obd_count        bufs_per_obdo = 1;
212         struct obdo     *oa;
213         obd_size         count = to;
214         obd_off          offset = (((obd_off)page->index) << PAGE_SHIFT);
215         obd_flag         flags = create ? OBD_BRW_CREATE : 0;
216         int              err;
217         struct iattr     iattr;
218
219         ENTRY;
220         oa = ll_oa_from_inode(inode, OBD_MD_FLNOTOBD);
221         if (! oa )
222                 RETURN(-ENOMEM);
223
224         SetPageUptodate(page);
225
226         if (!PageLocked(page))
227                 LBUG();
228
229         CDEBUG(D_INODE, "commit_page writing (at %d) to %d, count %Ld\n", 
230                from, to, (unsigned long long)count);
231
232         err = obd_brw(OBD_BRW_WRITE, ll_i2obdconn(inode), num_obdo, &oa,
233                       &bufs_per_obdo, &page, &count, &offset, &flags);
234         kunmap(page);
235
236         if ((iattr.ia_size = offset + to) > inode->i_size) {
237                 /* do NOT truncate when writing in the middle of a file */
238                 inode->i_size = iattr.ia_size;
239                 iattr.ia_valid = ATTR_SIZE;
240 #if 0
241                 err = ll_inode_setattr(inode, &iattr, 0);
242                 if (err) {
243                         CERROR("failed - %d.\n", err);
244                         err = -EIO;
245                 }
246 #endif
247         }
248
249         obdo_free(oa);
250         RETURN(err);
251 } /* ll_commit_write */
252
253 void ll_truncate(struct inode *inode)
254 {
255         struct obdo *oa;
256         int err;
257         ENTRY;
258
259         oa = ll_oa_from_inode(inode, OBD_MD_FLNOTOBD);
260         if ( !oa ) {
261                 CERROR("no memory to allocate obdo!\n");
262                 return; 
263         } 
264         
265         CDEBUG(D_INFO, "calling punch for %ld (%Lu bytes at 0)\n",
266                (long)oa->o_id, (unsigned long long)oa->o_size);
267         err = obd_punch(ll_i2obdconn(inode), oa, oa->o_size, 0);
268         obdo_free(oa);
269
270         if (err) {
271                 CERROR("obd_truncate fails (%d)\n", err);
272         }
273         EXIT;
274         return;
275 } /* ll_truncate */
276
277 int ll_direct_IO(int rw, struct inode *inode, struct kiobuf *iobuf,
278                  unsigned long blocknr, int blocksize)
279 {
280         int i;
281         obd_count        num_obdo = 1;
282         obd_count        bufs_per_obdo = iobuf->nr_pages;
283         struct obdo     *oa = NULL;
284         obd_size         *count = NULL;
285         obd_off          *offset = NULL;
286         obd_flag         *flags = NULL;
287         int              rc = 0;
288
289         ENTRY;
290
291         if (blocksize != PAGE_SIZE) {
292                 CERROR("direct_IO blocksize != PAGE_SIZE, what to do?\n");
293                 LBUG();
294         }
295
296         OBD_ALLOC(count, sizeof(obd_size) * bufs_per_obdo);
297         OBD_ALLOC(offset, sizeof(obd_off) * bufs_per_obdo);
298         OBD_ALLOC(flags, sizeof(obd_flag) * bufs_per_obdo);
299         if (!count || !offset || !flags)
300                 GOTO(out, rc = -ENOMEM);
301
302         /* NB: we can't use iobuf->maplist[i]->index for the offset
303          * instead of "blocknr" because ->index contains garbage.
304          */
305         for (i = 0; i < bufs_per_obdo; i++, blocknr++) {
306                 count[i] = PAGE_SIZE;
307                 offset[i] = (obd_off)blocknr << PAGE_SHIFT;
308                 flags[i] = OBD_BRW_CREATE;
309         }
310
311         oa = ll_oa_from_inode(inode, OBD_MD_FLNOTOBD);
312         if (!oa)
313                 GOTO(out, rc = -ENOMEM);
314
315         rc = obd_brw(rw, ll_i2obdconn(inode), num_obdo, &oa, &bufs_per_obdo,
316                      iobuf->maplist, count, offset, flags);
317         if (rc == 0)
318                 rc = bufs_per_obdo * PAGE_SIZE;
319
320  out:
321         obdo_free(oa);
322         OBD_FREE(flags, sizeof(obd_flag) * bufs_per_obdo);
323         OBD_FREE(offset, sizeof(obd_off) * bufs_per_obdo);
324         OBD_FREE(count, sizeof(obd_count) * bufs_per_obdo);
325         RETURN(rc);
326 }
327
328
329
330 struct address_space_operations ll_aops = {
331         readpage: ll_readpage,
332         writepage: ll_writepage,
333 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,17))
334         direct_IO: ll_direct_IO,
335 #endif
336         sync_page: block_sync_page,
337         prepare_write: ll_prepare_write, 
338         commit_write: ll_commit_write,
339         bmap: NULL
340 };