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