Whamcloud - gitweb
It's been a good day: chmod/chown and friends now work for Lustre Light.
[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
8 #include <linux/config.h>
9 #include <linux/kernel.h>
10 #include <linux/mm.h>
11 #include <linux/string.h>
12 #include <linux/stat.h>
13 #include <linux/errno.h>
14 #include <linux/locks.h>
15 #include <linux/unistd.h>
16
17 #include <asm/system.h>
18 #include <asm/uaccess.h>
19
20 #include <linux/fs.h>
21 #include <linux/stat.h>
22 #include <asm/uaccess.h>
23 #include <linux/vmalloc.h>
24 #include <asm/segment.h>
25 #include <linux/mm.h>
26 #include <linux/pagemap.h>
27 #include <linux/smp_lock.h>
28
29 #include <linux/obd_support.h>
30 #include <linux/lustre_lib.h>
31 #include <linux/lustre_idl.h>
32 #include <linux/lustre_mds.h>
33 #include <linux/lustre_light.h>
34
35 /*
36  * Add a page to the dirty page list.
37  */
38 void set_page_dirty(struct page *page)
39 {
40         if (!test_and_set_bit(PG_dirty, &page->flags)) {
41                 struct address_space *mapping = page->mapping;
42
43                 if (mapping) {
44                         spin_lock(&pagecache_lock);
45                         list_del(&page->list);
46                         list_add(&page->list, &mapping->dirty_pages);
47                         spin_unlock(&pagecache_lock);
48
49                         if (mapping->host)
50                                 mark_inode_dirty_pages(mapping->host);
51                 }
52         }
53 }
54
55 /*
56  * Remove page from dirty list
57  */
58 void __set_page_clean(struct page *page)
59 {
60         struct address_space *mapping = page->mapping;
61         struct inode *inode;
62         
63         if (!mapping)
64                 return;
65
66         spin_lock(&pagecache_lock);
67         list_del(&page->list);
68         list_add(&page->list, &mapping->clean_pages);
69
70         inode = mapping->host;
71         if (list_empty(&mapping->dirty_pages)) { 
72                 CDEBUG(D_INODE, "inode clean\n");
73                 inode->i_state &= ~I_DIRTY_PAGES;
74         }
75         spin_unlock(&pagecache_lock);
76         EXIT;
77 }
78
79 inline void set_page_clean(struct page *page)
80 {
81         if (PageDirty(page)) { 
82                 ClearPageDirty(page);
83                 __set_page_clean(page);
84         }
85 }
86
87 /* SYNCHRONOUS I/O to object storage for an inode -- object attr will be updated too */
88 static int ll_brw(int rw, struct inode *inode, struct page *page, int create)
89 {
90         obd_count        num_obdo = 1;
91         obd_count        bufs_per_obdo = 1;
92         struct obdo     *oa;
93         obd_size         count = PAGE_SIZE;
94         obd_off          offset = ((obd_off)page->index) << PAGE_SHIFT;
95         obd_flag         flags = create ? OBD_BRW_CREATE : 0;
96         int              err;
97
98         ENTRY;
99
100         oa = obdo_alloc();
101         if ( !oa ) {
102                 EXIT;
103                 return -ENOMEM;
104         }
105         oa->o_valid = OBD_MD_FLNOTOBD;
106         ll_from_inode(oa, inode);
107
108         err = obd_brw(rw, IID(inode), num_obdo, &oa, &bufs_per_obdo,
109                                &page, &count, &offset, &flags);
110         //if ( !err )
111         //      ll_to_inode(inode, oa); /* copy o_blocks to i_blocks */
112
113         obdo_free(oa);
114         EXIT;
115         return err;
116 } /* ll_brw */
117
118 extern void set_page_clean(struct page *);
119
120 /* SYNCHRONOUS I/O to object storage for an inode -- object attr will be updated too */
121 static int ll_commit_page(struct page *page, int create, int from, int to)
122 {
123         struct inode *inode = page->mapping->host;
124         obd_count        num_obdo = 1;
125         obd_count        bufs_per_obdo = 1;
126         struct obdo     *oa;
127         obd_size         count = to;
128         obd_off          offset = (((obd_off)page->index) << PAGE_SHIFT);
129         obd_flag         flags = create ? OBD_BRW_CREATE : 0;
130         int              err;
131
132         ENTRY;
133         oa = obdo_alloc();
134         if ( !oa ) {
135                 EXIT;
136                 return -ENOMEM;
137         }
138         oa->o_valid = OBD_MD_FLNOTOBD;
139         ll_from_inode(oa, inode);
140
141         CDEBUG(D_INODE, "commit_page writing (at %d) to %d, count %Ld\n", 
142                from, to, count);
143
144         err = obd_brw(WRITE, IID(inode), num_obdo, &oa, &bufs_per_obdo,
145                                &page, &count, &offset, &flags);
146         if ( !err ) {
147                 SetPageUptodate(page);
148                 set_page_clean(page);
149         }
150
151         //if ( !err )
152         //      ll_to_inode(inode, oa); /* copy o_blocks to i_blocks */
153
154         obdo_free(oa);
155         EXIT;
156         return err;
157 } /* ll_brw */
158
159
160 /* returns the page unlocked, but with a reference */
161 int ll_readpage(struct file *file, struct page *page)
162 {
163         struct inode *inode = page->mapping->host;
164         int rc;
165
166         ENTRY;
167
168         if ( ((inode->i_size + PAGE_CACHE_SIZE -1)>>PAGE_SHIFT) 
169              <= page->index) {
170                 memset(kmap(page), 0, PAGE_CACHE_SIZE);
171                 kunmap(page);
172                 goto readpage_out;
173         }
174
175         if (Page_Uptodate(page)) {
176                 EXIT;
177                 goto readpage_out;
178         }
179
180         rc = ll_brw(READ, inode, page, 0);
181         if ( rc ) {
182                 EXIT; 
183                 return rc;
184         } 
185         /* PDEBUG(page, "READ"); */
186
187  readpage_out:
188         SetPageUptodate(page);
189         obd_unlock_page(page);
190         EXIT;
191         return 0;
192 } /* ll_readpage */
193
194
195
196 /* returns the page unlocked, but with a reference */
197 int ll_dir_readpage(struct file *file, struct page *page)
198 {
199         struct inode *inode = page->mapping->host;
200         char *buf;
201         __u64 offset;
202         int rc = 0;
203         struct mds_rep_hdr *hdr;
204
205         ENTRY;
206
207         if ( ((inode->i_size + PAGE_CACHE_SIZE -1)>>PAGE_SHIFT) 
208              <= page->index) {
209                 memset(kmap(page), 0, PAGE_CACHE_SIZE);
210                 kunmap(page);
211                 goto readpage_out;
212         }
213
214         if (Page_Uptodate(page)) {
215                 EXIT;
216                 goto readpage_out;
217         }
218
219         offset = page->index << PAGE_SHIFT; 
220         buf = kmap(page);
221         rc = mdc_readpage(inode->i_ino, S_IFDIR, offset, buf, NULL, &hdr);
222         kunmap(buff); 
223         if ( rc ) {
224                 EXIT; 
225                 goto readpage_out;
226         } 
227
228         if ((rc = hdr->status)) {
229                 EXIT;
230                 goto readpage_out;
231         }
232
233         /* PDEBUG(page, "READ"); */
234
235         SetPageUptodate(page);
236  readpage_out:
237         unlock_page(page);
238         EXIT;
239         return rc;
240 } /* ll_dir_readpage */
241
242 int ll_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to)
243 {
244         struct inode *inode = page->mapping->host;
245         obd_off offset = ((obd_off)page->index) << PAGE_SHIFT;
246         int rc = 0;
247         ENTRY; 
248         
249         kmap(page);
250         if (Page_Uptodate(page)) { 
251                 EXIT;
252                 goto prepare_done;
253         }
254
255         if ( (from <= offset) && (to >= offset + PAGE_SIZE) ) {
256                 EXIT;
257                 return 0;
258         }
259         
260         rc = ll_brw(READ, inode, page, 0);
261         if ( !rc ) {
262                 SetPageUptodate(page);
263         } 
264
265  prepare_done:
266         set_page_dirty(page);
267         //SetPageDirty(page);
268         EXIT;
269         return rc;
270 }
271
272
273 /* select between SYNC and ASYNC I/O methods */
274 int ll_do_writepage(struct page *page, int sync)
275 {
276         struct inode *inode = page->mapping->host;
277         int err;
278
279         ENTRY;
280         /* PDEBUG(page, "WRITEPAGE"); */
281         /* XXX everything is synchronous now */
282         err = ll_brw(WRITE, inode, page, 1);
283
284         if ( !err ) {
285                 SetPageUptodate(page);
286                 set_page_clean(page);
287         }
288         /* PDEBUG(page,"WRITEPAGE"); */
289         EXIT;
290         return err;
291 } /* ll_do_writepage */
292
293
294
295 /* returns the page unlocked, but with a reference */
296 int ll_writepage(struct page *page)
297 {
298         int rc;
299         struct inode *inode = page->mapping->host;
300         ENTRY;
301         printk("---> writepage called ino %ld!\n", inode->i_ino);
302         BUG();
303         rc = ll_do_writepage(page, 1);
304         if ( !rc ) {
305                 set_page_clean(page);
306         } else {
307                 CDEBUG(D_INODE, "--> GRR %d\n", rc);
308         }
309         EXIT;
310         return rc;
311 }
312
313 void write_inode_pages(struct inode *inode)
314 {
315         struct list_head *tmp = &inode->i_mapping->dirty_pages;
316         
317         while ( (tmp = tmp->next) != &inode->i_mapping->dirty_pages) { 
318                 struct page *page;
319                 page = list_entry(tmp, struct page, list);
320                 ll_writepage(page);
321         }
322 }
323
324
325 int ll_commit_write(struct file *file, struct page *page, unsigned from, unsigned to)
326 {
327         struct inode *inode = page->mapping->host;
328         int rc = 0;
329         loff_t len = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to;
330         ENTRY;
331         CDEBUG(D_INODE, "commit write ino %ld (end at %Ld) from %d to %d ,ind %ld\n",
332                inode->i_ino, len, from, to, page->index);
333
334         rc = ll_commit_page(page, 1, from, to);
335
336         if (len > inode->i_size) {
337                 ll_set_size(inode, len);
338         }
339
340         kunmap(page);
341         EXIT;
342         return rc;
343 }
344
345
346 /*
347  * This does the "real" work of the write. The generic routine has
348  * allocated the page, locked it, done all the page alignment stuff
349  * calculations etc. Now we should just copy the data from user
350  * space and write it back to the real medium..
351  *
352  * If the writer ends up delaying the write, the writer needs to
353  * increment the page use counts until he is done with the page.
354  *
355  * Return value is the number of bytes written.
356  */
357 int ll_write_one_page(struct file *file, struct page *page,
358                          unsigned long offset, unsigned long bytes,
359                          const char * buf)
360 {
361         struct inode *inode = file->f_dentry->d_inode;
362         int err;
363
364         ENTRY;
365         /* We check for complete page writes here, as we then don't have to
366          * get the page before writing over everything anyways.
367          */
368         if ( !Page_Uptodate(page) && (offset != 0 || bytes != PAGE_SIZE) ) {
369                 err = ll_brw(READ, inode, page, 0);
370                 if ( err )
371                         return err;
372                 SetPageUptodate(page);
373         }
374
375         if (copy_from_user((u8*)page_address(page) + offset, buf, bytes))
376                 return -EFAULT;
377
378         lock_kernel();
379         err = ll_writepage(page);
380         unlock_kernel();
381
382         return (err < 0 ? err : bytes);
383 } /* ll_write_one_page */
384
385 /* 
386  * return an up to date page:
387  *  - if locked is true then is returned locked
388  *  - if create is true the corresponding disk blocks are created 
389  *  - page is held, i.e. caller must release the page
390  *
391  * modeled on NFS code.
392  */
393 struct page *ll_getpage(struct inode *inode, unsigned long offset,
394                            int create, int locked)
395 {
396         struct page * page;
397         int index;
398         int err;
399
400         ENTRY;
401
402         offset = offset & PAGE_CACHE_MASK;
403         CDEBUG(D_INFO, "ino: %ld, offset %ld, create %d, locked %d\n",
404                inode->i_ino, offset, create, locked);
405         index = offset >> PAGE_CACHE_SHIFT;
406
407         page = grab_cache_page(&inode->i_data, index);
408
409         /* Yuck, no page */
410         if (! page) {
411             printk(KERN_WARNING " grab_cache_page says no dice ...\n");
412             EXIT;
413             return NULL;
414         }
415
416         /* PDEBUG(page, "GETPAGE: got page - before reading\n"); */
417         /* now check if the data in the page is up to date */
418         if ( Page_Uptodate(page)) { 
419                 if (!locked) {
420                         if (PageLocked(page))
421                                 obd_unlock_page(page);
422                 } else {
423                         printk("file %s, line %d: expecting locked page\n",
424                                __FILE__, __LINE__); 
425                 }
426                 EXIT;
427                 return page;
428         } 
429
430         err = ll_brw(READ, inode, page, create);
431
432         if ( err ) {
433                 SetPageError(page);
434                 obd_unlock_page(page);
435                 EXIT;
436                 return page;
437         }
438
439         if ( !locked )
440                 obd_unlock_page(page);
441         SetPageUptodate(page);
442         /* PDEBUG(page,"GETPAGE - after reading"); */
443         EXIT;
444         return page;
445 } /* ll_getpage */
446
447
448 void ll_truncate(struct inode *inode)
449 {
450         struct obdo *oa;
451         int err;
452         ENTRY;
453
454         //ll_dequeue_pages(inode);
455
456         oa = obdo_alloc();
457         if ( !oa ) {
458                 /* XXX This would give an inconsistent FS, so deal with it as
459                  * best we can for now - an obdo on the stack is not pretty.
460                  */
461                 struct obdo obdo;
462
463                 printk(__FUNCTION__ ": obdo_alloc failed - using stack!\n");
464
465                 obdo.o_valid = OBD_MD_FLNOTOBD;
466                 ll_from_inode(&obdo, inode);
467
468                 err = obd_punch(IID(inode), &obdo, 0, obdo.o_size);
469         } else {
470                 oa->o_valid = OBD_MD_FLNOTOBD;
471                 ll_from_inode(oa, inode);
472
473                 CDEBUG(D_INFO, "calling punch for %ld (%Lu bytes at 0)\n",
474                        (long)oa->o_id, oa->o_size);
475                 err = obd_punch(IID(inode), oa, oa->o_size, 0);
476
477                 obdo_free(oa);
478         }
479
480         if (err) {
481                 printk(__FUNCTION__ ": obd_truncate fails (%d)\n", err);
482                 EXIT;
483                 return;
484         }
485         EXIT;
486 } /* ll_truncate */
487
488 struct address_space_operations ll_aops = {
489         readpage: ll_readpage,
490         writepage: ll_writepage,
491         sync_page: block_sync_page,
492         prepare_write: ll_prepare_write, 
493         commit_write: ll_commit_write,
494         bmap: NULL
495 };
496
497
498 struct address_space_operations ll_dir_aops = {
499         readpage: ll_dir_readpage
500 };