[PATCH] BLOCK: Don't call block_sync_page() from AFS [try #6]
[safe/jmp/linux-2.6] / fs / afs / file.c
1 /* file.c: AFS filesystem file handling
2  *
3  * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
4  * Written by David Howells (dhowells@redhat.com)
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version
9  * 2 of the License, or (at your option) any later version.
10  */
11
12 #include <linux/kernel.h>
13 #include <linux/module.h>
14 #include <linux/init.h>
15 #include <linux/sched.h>
16 #include <linux/slab.h>
17 #include <linux/fs.h>
18 #include <linux/pagemap.h>
19 #include <linux/buffer_head.h>
20 #include "volume.h"
21 #include "vnode.h"
22 #include <rxrpc/call.h>
23 #include "internal.h"
24
25 #if 0
26 static int afs_file_open(struct inode *inode, struct file *file);
27 static int afs_file_release(struct inode *inode, struct file *file);
28 #endif
29
30 static int afs_file_readpage(struct file *file, struct page *page);
31 static void afs_file_invalidatepage(struct page *page, unsigned long offset);
32 static int afs_file_releasepage(struct page *page, gfp_t gfp_flags);
33
34 struct inode_operations afs_file_inode_operations = {
35         .getattr        = afs_inode_getattr,
36 };
37
38 const struct address_space_operations afs_fs_aops = {
39         .readpage       = afs_file_readpage,
40         .set_page_dirty = __set_page_dirty_nobuffers,
41         .releasepage    = afs_file_releasepage,
42         .invalidatepage = afs_file_invalidatepage,
43 };
44
45 /*****************************************************************************/
46 /*
47  * deal with notification that a page was read from the cache
48  */
49 #ifdef AFS_CACHING_SUPPORT
50 static void afs_file_readpage_read_complete(void *cookie_data,
51                                             struct page *page,
52                                             void *data,
53                                             int error)
54 {
55         _enter("%p,%p,%p,%d", cookie_data, page, data, error);
56
57         if (error)
58                 SetPageError(page);
59         else
60                 SetPageUptodate(page);
61         unlock_page(page);
62
63 } /* end afs_file_readpage_read_complete() */
64 #endif
65
66 /*****************************************************************************/
67 /*
68  * deal with notification that a page was written to the cache
69  */
70 #ifdef AFS_CACHING_SUPPORT
71 static void afs_file_readpage_write_complete(void *cookie_data,
72                                              struct page *page,
73                                              void *data,
74                                              int error)
75 {
76         _enter("%p,%p,%p,%d", cookie_data, page, data, error);
77
78         unlock_page(page);
79
80 } /* end afs_file_readpage_write_complete() */
81 #endif
82
83 /*****************************************************************************/
84 /*
85  * AFS read page from file (or symlink)
86  */
87 static int afs_file_readpage(struct file *file, struct page *page)
88 {
89         struct afs_rxfs_fetch_descriptor desc;
90 #ifdef AFS_CACHING_SUPPORT
91         struct cachefs_page *pageio;
92 #endif
93         struct afs_vnode *vnode;
94         struct inode *inode;
95         int ret;
96
97         inode = page->mapping->host;
98
99         _enter("{%lu},{%lu}", inode->i_ino, page->index);
100
101         vnode = AFS_FS_I(inode);
102
103         BUG_ON(!PageLocked(page));
104
105         ret = -ESTALE;
106         if (vnode->flags & AFS_VNODE_DELETED)
107                 goto error;
108
109 #ifdef AFS_CACHING_SUPPORT
110         ret = cachefs_page_get_private(page, &pageio, GFP_NOIO);
111         if (ret < 0)
112                 goto error;
113
114         /* is it cached? */
115         ret = cachefs_read_or_alloc_page(vnode->cache,
116                                          page,
117                                          afs_file_readpage_read_complete,
118                                          NULL,
119                                          GFP_KERNEL);
120 #else
121         ret = -ENOBUFS;
122 #endif
123
124         switch (ret) {
125                 /* read BIO submitted and wb-journal entry found */
126         case 1:
127                 BUG(); // TODO - handle wb-journal match
128
129                 /* read BIO submitted (page in cache) */
130         case 0:
131                 break;
132
133                 /* no page available in cache */
134         case -ENOBUFS:
135         case -ENODATA:
136         default:
137                 desc.fid        = vnode->fid;
138                 desc.offset     = page->index << PAGE_CACHE_SHIFT;
139                 desc.size       = min((size_t) (inode->i_size - desc.offset),
140                                       (size_t) PAGE_SIZE);
141                 desc.buffer     = kmap(page);
142
143                 clear_page(desc.buffer);
144
145                 /* read the contents of the file from the server into the
146                  * page */
147                 ret = afs_vnode_fetch_data(vnode, &desc);
148                 kunmap(page);
149                 if (ret < 0) {
150                         if (ret==-ENOENT) {
151                                 _debug("got NOENT from server"
152                                        " - marking file deleted and stale");
153                                 vnode->flags |= AFS_VNODE_DELETED;
154                                 ret = -ESTALE;
155                         }
156
157 #ifdef AFS_CACHING_SUPPORT
158                         cachefs_uncache_page(vnode->cache, page);
159 #endif
160                         goto error;
161                 }
162
163                 SetPageUptodate(page);
164
165 #ifdef AFS_CACHING_SUPPORT
166                 if (cachefs_write_page(vnode->cache,
167                                        page,
168                                        afs_file_readpage_write_complete,
169                                        NULL,
170                                        GFP_KERNEL) != 0
171                     ) {
172                         cachefs_uncache_page(vnode->cache, page);
173                         unlock_page(page);
174                 }
175 #else
176                 unlock_page(page);
177 #endif
178         }
179
180         _leave(" = 0");
181         return 0;
182
183  error:
184         SetPageError(page);
185         unlock_page(page);
186
187         _leave(" = %d", ret);
188         return ret;
189
190 } /* end afs_file_readpage() */
191
192 /*****************************************************************************/
193 /*
194  * get a page cookie for the specified page
195  */
196 #ifdef AFS_CACHING_SUPPORT
197 int afs_cache_get_page_cookie(struct page *page,
198                               struct cachefs_page **_page_cookie)
199 {
200         int ret;
201
202         _enter("");
203         ret = cachefs_page_get_private(page,_page_cookie, GFP_NOIO);
204
205         _leave(" = %d", ret);
206         return ret;
207 } /* end afs_cache_get_page_cookie() */
208 #endif
209
210 /*****************************************************************************/
211 /*
212  * invalidate part or all of a page
213  */
214 static void afs_file_invalidatepage(struct page *page, unsigned long offset)
215 {
216         int ret = 1;
217
218         _enter("{%lu},%lu", page->index, offset);
219
220         BUG_ON(!PageLocked(page));
221
222         if (PagePrivate(page)) {
223 #ifdef AFS_CACHING_SUPPORT
224                 struct afs_vnode *vnode = AFS_FS_I(page->mapping->host);
225                 cachefs_uncache_page(vnode->cache,page);
226 #endif
227
228                 /* We release buffers only if the entire page is being
229                  * invalidated.
230                  * The get_block cached value has been unconditionally
231                  * invalidated, so real IO is not possible anymore.
232                  */
233                 if (offset == 0) {
234                         BUG_ON(!PageLocked(page));
235
236                         ret = 0;
237                         if (!PageWriteback(page))
238                                 ret = page->mapping->a_ops->releasepage(page,
239                                                                         0);
240                         /* possibly should BUG_ON(!ret); - neilb */
241                 }
242         }
243
244         _leave(" = %d", ret);
245 } /* end afs_file_invalidatepage() */
246
247 /*****************************************************************************/
248 /*
249  * release a page and cleanup its private data
250  */
251 static int afs_file_releasepage(struct page *page, gfp_t gfp_flags)
252 {
253         struct cachefs_page *pageio;
254
255         _enter("{%lu},%x", page->index, gfp_flags);
256
257         if (PagePrivate(page)) {
258 #ifdef AFS_CACHING_SUPPORT
259                 struct afs_vnode *vnode = AFS_FS_I(page->mapping->host);
260                 cachefs_uncache_page(vnode->cache, page);
261 #endif
262
263                 pageio = (struct cachefs_page *) page_private(page);
264                 set_page_private(page, 0);
265                 ClearPagePrivate(page);
266
267                 kfree(pageio);
268         }
269
270         _leave(" = 0");
271         return 0;
272 } /* end afs_file_releasepage() */