Whamcloud - gitweb
- Added DEBUG_SUBSYSTEMs
[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/lustre_lib.h>
31 #include <linux/lustre_idl.h>
32 #include <linux/lustre_mds.h>
33 #include <linux/lustre_light.h>
34
35 int ll_inode_setattr(struct inode *inode, struct iattr *attr, int do_trunc);
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                 printk(__FUNCTION__ ": 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         obdo_from_inode(oa, inode);
123         
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         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, IID(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 int ll_readpage(struct file *file, struct page *page)
191 {
192         struct inode *inode = page->mapping->host;
193         int rc;
194
195         ENTRY;
196
197         if ( ((inode->i_size + PAGE_CACHE_SIZE -1)>>PAGE_SHIFT) 
198              <= page->index) {
199                 memset(kmap(page), 0, PAGE_CACHE_SIZE);
200                 kunmap(page);
201                 goto readpage_out;
202         }
203
204         if (Page_Uptodate(page)) {
205                 EXIT;
206                 goto readpage_out;
207         }
208
209         rc = ll_brw(OBD_BRW_READ, inode, page, 0);
210         if ( rc ) {
211                 EXIT; 
212                 return rc;
213         } 
214
215  readpage_out:
216         SetPageUptodate(page);
217         obd_unlock_page(page);
218         EXIT;
219         return 0;
220 } /* ll_readpage */
221
222
223 int ll_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to)
224 {
225         struct inode *inode = page->mapping->host;
226         obd_off offset = ((obd_off)page->index) << PAGE_SHIFT;
227         int rc = 0;
228         ENTRY; 
229         
230         kmap(page);
231         if (Page_Uptodate(page)) { 
232                 EXIT;
233                 goto prepare_done;
234         }
235
236         if ( (from <= offset) && (to >= offset + PAGE_SIZE) ) {
237                 EXIT;
238                 return 0;
239         }
240         
241         rc = ll_brw(OBD_BRW_READ, inode, page, 0);
242         if ( !rc ) {
243                 SetPageUptodate(page);
244         } 
245
246  prepare_done:
247         set_page_dirty(page);
248         EXIT;
249         return rc;
250 }
251
252 /* returns the page unlocked, but with a reference */
253 int ll_writepage(struct page *page)
254 {
255         struct inode *inode = page->mapping->host;
256         int err;
257         ENTRY;
258
259         err = ll_brw(OBD_BRW_WRITE, inode, page, 1);
260         if ( !err ) {
261                 SetPageUptodate(page);
262                 set_page_clean(page);
263         } else {
264                 printk(__FUNCTION__ ": ll_brw failure %d\n", err);
265         }
266         EXIT;
267         return err;
268 }
269
270 /* SYNCHRONOUS I/O to object storage for an inode -- object attr will be updated too */
271 int ll_commit_write(struct file *file, struct page *page, 
272                     unsigned from, unsigned to)
273 {
274         int create = 1;
275         struct inode *inode = page->mapping->host;
276         obd_count        num_obdo = 1;
277         obd_count        bufs_per_obdo = 1;
278         struct obdo     *oa;
279         obd_size         count = to;
280         obd_off          offset = (((obd_off)page->index) << PAGE_SHIFT) + to;
281         obd_flag         flags = create ? OBD_BRW_CREATE : 0;
282         int              err;
283         struct iattr     iattr;
284
285         ENTRY;
286         oa = ll_oa_from_inode(inode, OBD_MD_FLNOTOBD);
287         if (! oa ) { 
288                 return -ENOMEM;
289         }
290
291         CDEBUG(D_INODE, "commit_page writing (at %d) to %d, count %Ld\n", 
292                from, to, count);
293
294         err = obd_brw(OBD_BRW_WRITE, IID(inode), num_obdo, &oa, &bufs_per_obdo,
295                       &page, &count, &offset, &flags);
296         if ( !err ) {
297                 SetPageUptodate(page);
298                 set_page_clean(page);
299         }
300         kunmap(page);
301
302         if (offset > inode->i_size) {
303                 iattr.ia_valid = ATTR_SIZE;
304                 iattr.ia_size = offset;
305                 /* do NOT truncate */
306                 err = ll_inode_setattr(inode, &iattr, 0);
307                 if (err) {
308                         printk(__FUNCTION__ ": failed - %d.\n", err);
309                         obdo_free(oa);
310                         EXIT;
311                         return -EIO;
312                 }
313         }
314
315         obdo_free(oa);
316         EXIT;
317         return err;
318 } /* ll_brw */
319
320 void ll_truncate(struct inode *inode)
321 {
322         struct obdo *oa;
323         int err;
324         ENTRY;
325
326         oa = ll_oa_from_inode(inode, OBD_MD_FLNOTOBD);
327         if ( !oa ) {
328                 printk(__FUNCTION__ ": no memory to allocate obdo!\n");
329                 return; 
330         } 
331         
332         CDEBUG(D_INFO, "calling punch for %ld (%Lu bytes at 0)\n",
333                (long)oa->o_id, oa->o_size);
334         err = obd_punch(IID(inode), oa, oa->o_size, 0);
335         obdo_free(oa);
336
337         if (err) {
338                 printk(__FUNCTION__ ": obd_truncate fails (%d)\n", err);
339         }
340         EXIT;
341         return; 
342 } /* ll_truncate */
343
344 struct address_space_operations ll_aops = {
345         readpage: ll_readpage,
346         writepage: ll_writepage,
347         sync_page: block_sync_page,
348         prepare_write: ll_prepare_write, 
349         commit_write: ll_commit_write,
350         bmap: NULL
351 };
352