Whamcloud - gitweb
obdsync/*: added to CVS
[fs/lustre-release.git] / lustre / obdfs / rw.c
1 /*
2  * OBDFS Super operations
3  *
4  * Copryright (C) 1999 Stelias Computing Inc, 
5  *                (author Peter J. Braam <braam@stelias.com>)
6  * Copryright (C) 1999 Seagate Technology Inc.
7  */
8
9
10 #include <linux/config.h>
11 #include <linux/kernel.h>
12 #include <linux/mm.h>
13 #include <linux/string.h>
14 #include <linux/stat.h>
15 #include <linux/errno.h>
16 #include <linux/locks.h>
17 #include <linux/unistd.h>
18
19 #include <asm/system.h>
20 #include <asm/uaccess.h>
21
22 #include <linux/fs.h>
23 #include <linux/stat.h>
24 #include <asm/uaccess.h>
25 #include <linux/vmalloc.h>
26 #include <asm/segment.h>
27 #include <linux/mm.h>
28 #include <linux/pagemap.h>
29 #include <linux/smp_lock.h>
30
31 #include <linux/obd_support.h>
32 #include <linux/obd_ext2.h>
33 #include <linux/obdfs.h>
34
35 int console_loglevel;
36
37 /* VFS super_block ops */
38
39 #if 0
40 int obdfs_brw(struct inode *dir, int rw, struct page *page, int create)
41 {
42         return iops(dir)->o_brw(rw, iid(dir), dir, page, create);
43 }
44 #endif
45
46 static kmem_cache_t *obdfs_wreq_cachep;
47
48 int obdfs_init_wreqcache(void)
49 {
50         /* XXX need to free this somewhere? */
51         ENTRY;
52         obdfs_wreq_cachep = kmem_cache_create("obdfs_wreq",
53                                               sizeof(struct obdfs_wreq),
54                                               0, SLAB_HWCACHE_ALIGN,
55                                               NULL, NULL);
56         if (obdfs_wreq_cachep == NULL) {
57                 EXIT;
58                 return -ENOMEM;
59         }
60         EXIT;
61         return 0;
62 }
63
64 /*
65  * Find a specific page in the page cache.  If it is found, we return
66  * the write request struct associated with it, if not found return NULL.
67  */
68 static struct obdfs_wreq *
69 obdfs_find_in_page_cache(struct inode *inode, struct page *page)
70 {
71         struct list_head *list_head = &OBD_LIST(inode);
72         struct obdfs_wreq *head, *wreq;
73
74         ENTRY;
75         CDEBUG(D_INODE, "looking for inode %ld page %p\n", inode->i_ino, page);
76         if (list_empty(list_head)) {
77                 CDEBUG(D_INODE, "empty list\n");
78                 EXIT;
79                 return NULL;
80         }
81         wreq = head = WREQ(list_head->next);
82         do {
83                 CDEBUG(D_INODE, "checking page %p\n", wreq->wb_page);
84                 if (wreq->wb_page == page) {
85                         CDEBUG(D_INODE, "found page %p in list\n", page);
86                         EXIT;
87                         return wreq;
88                 }
89         } while ((wreq = WB_NEXT(wreq)) != head);
90
91         EXIT;
92         return NULL;
93 }
94
95 /* returns the page unlocked, but with a reference */
96 int obdfs_readpage(struct dentry *dentry, struct page *page)
97 {
98         struct inode *inode = dentry->d_inode;
99         struct obdfs_wreq *wreq;
100         int rc = 0;
101
102         ENTRY;
103         /* XXX flush stuff */
104         wreq = obdfs_find_in_page_cache(inode, page);
105         if (!wreq) {
106                 PDEBUG(page, "READ");
107                 rc =  iops(inode)->o_brw(READ, iid(inode),inode, page, 0);
108                 if (rc == PAGE_SIZE ) {
109                         SetPageUptodate(page);
110                         UnlockPage(page);
111                 } 
112                 PDEBUG(page, "READ");
113                 if ( rc == PAGE_SIZE ) 
114                         rc = 0;
115         } 
116         EXIT;
117         return rc;
118 }
119
120 /*
121  * Remove a writeback request from a list
122  */
123 static inline int
124 obdfs_remove_from_page_cache(struct obdfs_wreq *wreq)
125 {
126         struct inode *inode = wreq->wb_inode;
127         struct page *page = wreq->wb_page;
128         int rc;
129
130         ENTRY;
131         CDEBUG(D_INODE, "removing inode %ld page %p, wreq: %p\n",
132                inode->i_ino, page, wreq);
133         rc = iops(inode)->o_brw(WRITE, iid(inode), inode, page, 1);
134         /* XXX probably should handle error here somehow.  I think that
135          *     ext2 also does the same thing - discard write even if error?
136          */
137         put_page(page);
138         list_del(&wreq->wb_list);
139         kmem_cache_free(obdfs_wreq_cachep, wreq);
140
141         EXIT;
142         return rc;
143 }
144
145 /*
146  * Add a page to the write request cache list for later writing
147  */
148 static int
149 obdfs_add_to_page_cache(struct inode *inode, struct page *page)
150 {
151         struct obdfs_wreq *wreq;
152
153         ENTRY;
154         wreq = kmem_cache_alloc(obdfs_wreq_cachep, SLAB_KERNEL);
155         CDEBUG(D_INODE, "adding inode %ld page %p, wreq: %p\n",
156                inode->i_ino, page, wreq);
157         if (!wreq) {
158                 EXIT;
159                 return -ENOMEM;
160         }
161         memset(wreq, 0, sizeof(*wreq)); 
162
163         wreq->wb_page = page;
164         wreq->wb_inode = inode;
165
166         get_page(wreq->wb_page);
167         list_add(&wreq->wb_list, &OBD_LIST(inode));
168
169         /* For testing purposes, we write out the page here.
170          * In the future, a flush daemon will write out the page.
171          */
172         wreq = obdfs_find_in_page_cache(inode, page);
173         if (!wreq) {
174                 CDEBUG(D_INODE, "XXXX Can't find page after adding it!!!\n");
175                 return -EINVAL;
176         } else
177                 return obdfs_remove_from_page_cache(wreq);
178
179         return 0;
180 }
181
182
183 /* returns the page unlocked, but with a reference */
184 int obdfs_writepage(struct dentry *dentry, struct page *page)
185 {
186         struct inode *inode = dentry->d_inode;
187         int rc;
188
189         ENTRY;
190         PDEBUG(page, "WRITEPAGE");
191         /* XXX flush stuff */
192         rc = obdfs_add_to_page_cache(inode, page);
193
194         if (!rc)
195                 SetPageUptodate(page);
196         PDEBUG(page,"WRITEPAGE");
197         return rc;
198 }
199
200 /*
201  * This does the "real" work of the write. The generic routine has
202  * allocated the page, locked it, done all the page alignment stuff
203  * calculations etc. Now we should just copy the data from user
204  * space and write it back to the real medium..
205  *
206  * If the writer ends up delaying the write, the writer needs to
207  * increment the page use counts until he is done with the page.
208  */
209 int obdfs_write_one_page(struct file *file, struct page *page, unsigned long offset, unsigned long bytes, const char * buf)
210 {
211         long status;
212         struct inode *inode = file->f_dentry->d_inode;
213
214         ENTRY;
215         if ( !Page_Uptodate(page) ) {
216                 status =  iops(inode)->o_brw(READ, iid(inode), inode, page, 1);
217                 if (status == PAGE_SIZE ) {
218                         SetPageUptodate(page);
219                 } else { 
220                         return status;
221                 }
222         }
223         bytes -= copy_from_user((u8*)page_address(page) + offset, buf, bytes);
224         status = -EFAULT;
225
226         if (bytes) {
227                 lock_kernel();
228                 status = obdfs_writepage(file->f_dentry, page);
229                 unlock_kernel();
230         }
231         EXIT;
232         if ( status != PAGE_SIZE ) 
233                 return status;
234         else
235                 return bytes;
236 }
237
238
239
240
241
242 void report_inode(struct page * page) {
243         struct inode *inode = (struct inode *)0;
244         int offset = (int)&inode->i_data;
245         inode = (struct inode *)( (char *)page->mapping - offset);
246         if ( inode->i_sb->s_magic == 0x4711 )
247                 printk("----> ino %ld , dev %d\n", inode->i_ino, inode->i_dev);
248 }
249
250 /* 
251    return an up to date page:
252     - if locked is true then is returned locked
253     - if create is true the corresponding disk blocks are created 
254     - page is held, i.e. caller must release the page
255
256    modeled on NFS code.
257 */
258 struct page *obdfs_getpage(struct inode *inode, unsigned long offset, int create, int locked)
259 {
260         struct page *page_cache;
261         struct page ** hash;
262         struct page * page;
263         int rc;
264
265         ENTRY;
266
267         offset = offset & PAGE_CACHE_MASK;
268         CDEBUG(D_INODE, "\n");
269         
270         page = NULL;
271         page_cache = page_cache_alloc();
272         if ( ! page_cache ) 
273                 return NULL;
274         CDEBUG(D_INODE, "page_cache %p\n", page_cache);
275
276         hash = page_hash(&inode->i_data, offset);
277         page = grab_cache_page(&inode->i_data, offset);
278
279         PDEBUG(page, "GETPAGE: got page - before reading\n");
280         /* now check if the data in the page is up to date */
281         if ( Page_Uptodate(page)) { 
282                 if (!locked)
283                         UnlockPage(page);
284                 EXIT;
285                 return page;
286         } 
287
288         /* it's not: read it */
289         if (! page) {
290             printk("get_page_map says no dice ...\n");
291             return 0;
292         }
293
294         rc = iops(inode)->o_brw(READ, iid(inode), inode, page, create);
295         if ( rc != PAGE_SIZE ) {
296                 SetPageError(page);
297                 UnlockPage(page);
298                 return page;
299         }
300
301         if ( !locked )
302                 UnlockPage(page);
303         SetPageUptodate(page);
304         PDEBUG(page,"GETPAGE - after reading");
305         EXIT;
306         return page;
307 }
308
309