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