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