Whamcloud - gitweb
cdb7bd63e9c74156749bc59f053e94b67ee85470
[fs/lustre-release.git] / lustre / obdfs / rw.c
1 /*
2  * OBDFS Super operations
3  *
4  * Copyright (C) 1996, 1997, Olaf Kirch <okir@monad.swb.de>
5  * Copryright (C) 1999 Stelias Computing Inc, 
6  *                (author Peter J. Braam <braam@stelias.com>)
7  * Copryright (C) 1999 Seagate Technology Inc.
8  */
9
10
11 #include <linux/config.h>
12 #include <linux/kernel.h>
13 #include <linux/mm.h>
14 #include <linux/string.h>
15 #include <linux/stat.h>
16 #include <linux/errno.h>
17 #include <linux/locks.h>
18 #include <linux/unistd.h>
19
20 #include <asm/system.h>
21 #include <asm/uaccess.h>
22
23 #include <linux/fs.h>
24 #include <linux/stat.h>
25 #include <asm/uaccess.h>
26 #include <linux/vmalloc.h>
27 #include <asm/segment.h>
28 #include <linux/mm.h>
29 #include <linux/pagemap.h>
30 #include <linux/smp_lock.h>
31
32 #include <linux/obd_support.h>
33 #include <linux/obd_ext2.h>
34 #include <linux/obdfs.h>
35
36 int console_loglevel;
37
38 /* SYNCHRONOUS I/O for an inode */
39 static int obdfs_brw(int rw, struct inode *inode, struct page *page, int create)
40 {
41         obd_count        num_io = 1;
42         struct obdo     *oa;
43         char            *buf = (char *)page_address(page);
44         obd_size         size = PAGE_SIZE;
45         obd_size        *count = &size;
46         obd_off          offset = ((obd_off)page->index) << PAGE_SHIFT;
47         obd_flag         flags = create ? OBD_BRW_CREATE : 0;
48         int              err;
49
50         ENTRY;
51         oa = obdo_fromid(IID(inode), inode->i_ino, OBD_MD_FLNOTOBD);
52         if ( IS_ERR(oa) ) {
53                 EXIT;
54                 return PTR_ERR(oa);
55         }
56         obdfs_from_inode(oa, inode);
57
58         err = IOPS(inode, brw)(rw, IID(inode), &num_io, &oa, &buf, &count,
59                                &offset, &flags);
60
61         if ( !err )
62                 obdfs_to_inode(inode, oa); /* copy o_blocks to i_blocks */
63
64         obdo_free(oa);
65         
66         EXIT;
67         return err;
68 } /* obdfs_brw */
69
70 /* returns the page unlocked, but with a reference */
71 int obdfs_readpage(struct dentry *dentry, struct page *page)
72 {
73         struct inode *inode = dentry->d_inode;
74         int rc;
75
76         ENTRY;
77         PDEBUG(page, "READ");
78         rc = obdfs_brw(READ, inode, page, 0);
79         if ( !rc ) {
80                 SetPageUptodate(page);
81                 UnlockPage(page);
82         } 
83         PDEBUG(page, "READ");
84         EXIT;
85         return rc;
86 } /* obdfs_readpage */
87
88 static kmem_cache_t *obdfs_pgrq_cachep = NULL;
89
90 int obdfs_init_pgrqcache(void)
91 {
92         ENTRY;
93         if (obdfs_pgrq_cachep == NULL) {
94                 CDEBUG(D_INODE, "allocating obdfs_pgrq_cache\n");
95                 obdfs_pgrq_cachep = kmem_cache_create("obdfs_pgrq",
96                                                       sizeof(struct obdfs_pgrq),
97                                                       0, SLAB_HWCACHE_ALIGN,
98                                                       NULL, NULL);
99                 if (obdfs_pgrq_cachep == NULL) {
100                         EXIT;
101                         return -ENOMEM;
102                 } else {
103                         CDEBUG(D_INODE, "allocated cache at %p\n",
104                                obdfs_pgrq_cachep);
105                 }
106         } else {
107                 CDEBUG(D_INODE, "using existing cache at %p\n",
108                        obdfs_pgrq_cachep);
109         }
110         EXIT;
111         return 0;
112 } /* obdfs_init_wreqcache */
113
114 void obdfs_cleanup_pgrqcache(void)
115 {
116         ENTRY;
117         if (obdfs_pgrq_cachep != NULL) {
118                 CDEBUG(D_INODE, "destroying obdfs_pgrqcache at %p\n",
119                        obdfs_pgrq_cachep);
120                 if (kmem_cache_destroy(obdfs_pgrq_cachep))
121                         printk(KERN_INFO "obd_cleanup_pgrqcache: unable to free all of cache\n");
122         } else
123                 printk(KERN_INFO "obd_cleanup_pgrqcache: called with NULL cache pointer\n");
124
125         EXIT;
126 } /* obdfs_cleanup_wreqcache */
127
128
129 /*
130  * Find a specific page in the page cache.  If it is found, we return
131  * the write request struct associated with it, if not found return NULL.
132  */
133 static struct obdfs_pgrq *
134 obdfs_find_in_page_cache(struct inode *inode, struct page *page)
135 {
136         struct list_head *page_list = &OBDFS_LIST(inode);
137         struct list_head *tmp;
138         struct obdfs_pgrq *pgrq;
139
140         ENTRY;
141         CDEBUG(D_INODE, "looking for inode %ld page %p\n", inode->i_ino, page);
142         if (list_empty(page_list)) {
143                 CDEBUG(D_INODE, "empty list\n");
144                 EXIT;
145                 return NULL;
146         }
147         tmp = page_list;
148         while ( (tmp = tmp->next) != page_list ) {
149                 pgrq = list_entry(tmp, struct obdfs_pgrq, rq_list);
150                 CDEBUG(D_INODE, "checking page %p\n", pgrq->rq_page);
151                 if (pgrq->rq_page == page) {
152                         CDEBUG(D_INODE, "found page %p in list\n", page);
153                         EXIT;
154                         return pgrq;
155                 }
156         } 
157
158         EXIT;
159         return NULL;
160 } /* obdfs_find_in_page_cache */
161
162
163 /*
164  * Remove a writeback request from a list
165  */
166 static inline int
167 obdfs_remove_from_page_cache(struct obdfs_pgrq *pgrq)
168 {
169         struct inode *inode = pgrq->rq_inode;
170         struct page *page = pgrq->rq_page;
171         int err;
172
173         ENTRY;
174         CDEBUG(D_INODE, "writing inode %ld page %p, pgrq: %p\n",
175                inode->i_ino, page, pgrq);
176         OIDEBUG(inode);
177         PDEBUG(page, "REM_CACHE");
178         err = obdfs_brw(WRITE, inode, page, 1);
179         /* XXX probably should handle error here somehow.  I think that
180          *     ext2 also does the same thing - discard write even if error?
181          */
182         put_page(page);
183         list_del(&pgrq->rq_list);
184         kmem_cache_free(obdfs_pgrq_cachep, pgrq);
185         OIDEBUG(inode);
186
187         EXIT;
188         return err;
189 } /* obdfs_remove_from_page_cache */
190
191 /*
192  * Add a page to the write request cache list for later writing
193  * ASYNCHRONOUS write method.
194  */
195 static int obdfs_add_to_page_cache(struct inode *inode, struct page *page)
196 {
197         struct obdfs_pgrq *pgrq;
198
199         ENTRY;
200         pgrq = kmem_cache_alloc(obdfs_pgrq_cachep, SLAB_KERNEL);
201         CDEBUG(D_INODE, "adding inode %ld page %p, pgrq: %p\n",
202                inode->i_ino, page, pgrq);
203         if (!pgrq) {
204                 EXIT;
205                 return -ENOMEM;
206         }
207         memset(pgrq, 0, sizeof(*pgrq)); 
208
209         pgrq->rq_page = page;
210         pgrq->rq_inode = inode;
211
212         get_page(pgrq->rq_page);
213         list_add(&pgrq->rq_list, &OBDFS_LIST(inode));
214
215         /* For testing purposes, we write out the page here.
216          * In the future, a flush daemon will write out the page.
217         return 0;
218          */
219         pgrq = obdfs_find_in_page_cache(inode, page);
220         if (!pgrq) {
221                 CDEBUG(D_INODE, "XXXX Can't find page after adding it!!!\n");
222                 EXIT;
223                 return -EINVAL;
224         } 
225                 
226         return obdfs_remove_from_page_cache(pgrq);
227 } /* obdfs_add_to_page_cache */
228
229
230 /* select between SYNC and ASYNC I/O methods */
231 int obdfs_do_writepage(struct inode *inode, struct page *page, int sync)
232 {
233         int err;
234
235         ENTRY;
236         PDEBUG(page, "WRITEPAGE");
237         if ( sync )
238                 err = obdfs_brw(WRITE, inode, page, 1);
239         else
240                 err = obdfs_add_to_page_cache(inode, page);
241                 
242         if ( !err )
243                 SetPageUptodate(page);
244         PDEBUG(page,"WRITEPAGE");
245         return err;
246 } /* obdfs_do_writepage */
247
248 /* returns the page unlocked, but with a reference */
249 int obdfs_writepage(struct dentry *dentry, struct page *page)
250 {
251         return obdfs_do_writepage(dentry->d_inode, page, 0);
252 }
253
254 /*
255  * This does the "real" work of the write. The generic routine has
256  * allocated the page, locked it, done all the page alignment stuff
257  * calculations etc. Now we should just copy the data from user
258  * space and write it back to the real medium..
259  *
260  * If the writer ends up delaying the write, the writer needs to
261  * increment the page use counts until he is done with the page.
262  *
263  * Return value is the number of bytes written.
264  */
265 int obdfs_write_one_page(struct file *file, struct page *page,
266                           unsigned long offset, unsigned long bytes,
267                           const char * buf)
268 {
269         struct inode *inode = file->f_dentry->d_inode;
270         int err;
271
272         ENTRY;
273         if ( !Page_Uptodate(page) ) {
274                 err = obdfs_brw(READ, inode, page, 1);
275                 if ( !err )
276                         SetPageUptodate(page);
277                 else
278                         return err;
279         }
280
281         if (copy_from_user((u8*)page_address(page) + offset, buf, bytes))
282                 return -EFAULT;
283
284         lock_kernel();
285         err = obdfs_writepage(file->f_dentry, page);
286         unlock_kernel();
287
288         return (err < 0 ? err : bytes);
289 } /* obdfs_write_one_page */
290
291 /* 
292    return an up to date page:
293     - if locked is true then is returned locked
294     - if create is true the corresponding disk blocks are created 
295     - page is held, i.e. caller must release the page
296
297    modeled on NFS code.
298 */
299 struct page *obdfs_getpage(struct inode *inode, unsigned long offset, int create, int locked)
300 {
301         struct page *page_cache;
302         struct page ** hash;
303         struct page * page;
304         int err;
305
306         ENTRY;
307
308         offset = offset & PAGE_CACHE_MASK;
309         CDEBUG(D_INODE, "\n");
310         
311         page = NULL;
312         page_cache = page_cache_alloc();
313         if ( ! page_cache ) {
314                 EXIT;
315                 return NULL;
316         }
317         CDEBUG(D_INODE, "page_cache %p\n", page_cache);
318
319         hash = page_hash(&inode->i_data, offset);
320         page = grab_cache_page(&inode->i_data, offset);
321
322         /* Yuck, no page */
323         if (! page) {
324             printk("grab_cache_page says no dice ...\n");
325             EXIT;
326             return 0;
327         }
328
329         PDEBUG(page, "GETPAGE: got page - before reading\n");
330         /* now check if the data in the page is up to date */
331         if ( Page_Uptodate(page)) { 
332                 if (!locked)
333                         UnlockPage(page);
334                 EXIT;
335                 return page;
336         } 
337
338         err = obdfs_brw(READ, inode, page, create);
339
340         if ( err ) {
341                 SetPageError(page);
342                 UnlockPage(page);
343                 EXIT;
344                 return page;
345         }
346
347         if ( !locked )
348                 UnlockPage(page);
349         SetPageUptodate(page);
350         PDEBUG(page,"GETPAGE - after reading");
351         EXIT;
352         return page;
353 } /* obdfs_getpage */
354
355