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