Whamcloud - gitweb
- more of the locking infrastructure.
[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                 LBUG();
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                 LBUG();
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         /* We're completely overwriting an existing page, so _don't_ set it up
251          * to date until commit_write */
252         if (from == 0 && to == PAGE_SIZE) {
253                 memset(addr, 0, PAGE_SIZE);
254                 RETURN(0);
255         }
256
257         rc = ll_brw(OBD_BRW_READ, inode, page, 0);
258
259  prepare_done:
260         if ( !rc )
261                 SetPageUptodate(page);
262
263         EXIT;
264         return rc;
265 }
266
267 /* returns the page unlocked, but with a reference */
268 static int ll_writepage(struct page *page)
269 {
270         struct inode *inode = page->mapping->host;
271         int err;
272         ENTRY;
273
274         LBUG();
275
276         if (!PageLocked(page))
277                 LBUG();
278
279         err = ll_brw(OBD_BRW_WRITE, inode, page, 1);
280         if ( !err ) {
281                 //SetPageUptodate(page);
282                 set_page_clean(page);
283         } else {
284                 CERROR("ll_brw failure %d\n", err);
285         }
286         UnlockPage(page); 
287         EXIT;
288         return err;
289 }
290
291 /* SYNCHRONOUS I/O to object storage for an inode -- object attr will be updated
292  * too */
293 static int ll_commit_write(struct file *file, struct page *page,
294                            unsigned from, unsigned to)
295 {
296         int create = 1;
297         struct inode *inode = page->mapping->host;
298         obd_count        num_obdo = 1;
299         obd_count        bufs_per_obdo = 1;
300         struct obdo     *oa;
301         obd_size         count = to;
302         obd_off          offset = (((obd_off)page->index) << PAGE_SHIFT);
303         obd_flag         flags = create ? OBD_BRW_CREATE : 0;
304         int              err;
305         struct iattr     iattr;
306
307         ENTRY;
308         oa = ll_oa_from_inode(inode, OBD_MD_FLNOTOBD);
309         if (! oa )
310                 RETURN(-ENOMEM);
311
312         SetPageUptodate(page);
313
314         if (!PageLocked(page))
315                 LBUG();
316
317         CDEBUG(D_INODE, "commit_page writing (at %d) to %d, count %Ld\n", 
318                from, to, count);
319
320         err = obd_brw(OBD_BRW_WRITE, ll_i2obdconn(inode), num_obdo, &oa,
321                       &bufs_per_obdo, &page, &count, &offset, &flags);
322         kunmap(page);
323
324         if (offset + to > inode->i_size) {
325                 iattr.ia_valid = ATTR_SIZE;
326                 iattr.ia_size = offset + to;
327                 /* do NOT truncate */
328                 err = ll_inode_setattr(inode, &iattr, 0);
329                 if (err) {
330                         CERROR("failed - %d.\n", err);
331                         err = -EIO;
332                 }
333         }
334
335         obdo_free(oa);
336         EXIT;
337         return err;
338 } /* ll_commit_write */
339
340 void ll_truncate(struct inode *inode)
341 {
342         struct obdo *oa;
343         int err;
344         ENTRY;
345
346         oa = ll_oa_from_inode(inode, OBD_MD_FLNOTOBD);
347         if ( !oa ) {
348                 CERROR("no memory to allocate obdo!\n");
349                 return; 
350         } 
351         
352         CDEBUG(D_INFO, "calling punch for %ld (%Lu bytes at 0)\n",
353                (long)oa->o_id, oa->o_size);
354         err = obd_punch(ll_i2obdconn(inode), oa, oa->o_size, 0);
355         obdo_free(oa);
356
357         if (err) {
358                 CERROR("obd_truncate fails (%d)\n", err);
359         }
360         EXIT;
361         return; 
362 } /* ll_truncate */
363
364 struct address_space_operations ll_aops = {
365         readpage: ll_readpage,
366         writepage: ll_writepage,
367         sync_page: block_sync_page,
368         prepare_write: ll_prepare_write, 
369         commit_write: ll_commit_write,
370         bmap: NULL
371 };
372