]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - fs/afs/file.c
Merge branch 'trivial-2.6.23' of git://git.kernel.dk/data/git/linux-2.6-block
[karo-tx-linux.git] / fs / afs / file.c
1 /* AFS filesystem file handling
2  *
3  * Copyright (C) 2002, 2007 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/slab.h>
16 #include <linux/fs.h>
17 #include <linux/pagemap.h>
18 #include <linux/writeback.h>
19 #include "internal.h"
20
21 static int afs_readpage(struct file *file, struct page *page);
22 static void afs_invalidatepage(struct page *page, unsigned long offset);
23 static int afs_releasepage(struct page *page, gfp_t gfp_flags);
24 static int afs_launder_page(struct page *page);
25
26 const struct file_operations afs_file_operations = {
27         .open           = afs_open,
28         .release        = afs_release,
29         .llseek         = generic_file_llseek,
30         .read           = do_sync_read,
31         .write          = do_sync_write,
32         .aio_read       = generic_file_aio_read,
33         .aio_write      = afs_file_write,
34         .mmap           = generic_file_readonly_mmap,
35         .sendfile       = generic_file_sendfile,
36         .fsync          = afs_fsync,
37 };
38
39 const struct inode_operations afs_file_inode_operations = {
40         .getattr        = afs_getattr,
41         .setattr        = afs_setattr,
42         .permission     = afs_permission,
43 };
44
45 const struct address_space_operations afs_fs_aops = {
46         .readpage       = afs_readpage,
47         .set_page_dirty = afs_set_page_dirty,
48         .launder_page   = afs_launder_page,
49         .releasepage    = afs_releasepage,
50         .invalidatepage = afs_invalidatepage,
51         .prepare_write  = afs_prepare_write,
52         .commit_write   = afs_commit_write,
53         .writepage      = afs_writepage,
54         .writepages     = afs_writepages,
55 };
56
57 /*
58  * open an AFS file or directory and attach a key to it
59  */
60 int afs_open(struct inode *inode, struct file *file)
61 {
62         struct afs_vnode *vnode = AFS_FS_I(inode);
63         struct key *key;
64         int ret;
65
66         _enter("{%x:%u},", vnode->fid.vid, vnode->fid.vnode);
67
68         key = afs_request_key(vnode->volume->cell);
69         if (IS_ERR(key)) {
70                 _leave(" = %ld [key]", PTR_ERR(key));
71                 return PTR_ERR(key);
72         }
73
74         ret = afs_validate(vnode, key);
75         if (ret < 0) {
76                 _leave(" = %d [val]", ret);
77                 return ret;
78         }
79
80         file->private_data = key;
81         _leave(" = 0");
82         return 0;
83 }
84
85 /*
86  * release an AFS file or directory and discard its key
87  */
88 int afs_release(struct inode *inode, struct file *file)
89 {
90         struct afs_vnode *vnode = AFS_FS_I(inode);
91
92         _enter("{%x:%u},", vnode->fid.vid, vnode->fid.vnode);
93
94         key_put(file->private_data);
95         _leave(" = 0");
96         return 0;
97 }
98
99 /*
100  * deal with notification that a page was read from the cache
101  */
102 #ifdef AFS_CACHING_SUPPORT
103 static void afs_readpage_read_complete(void *cookie_data,
104                                        struct page *page,
105                                        void *data,
106                                        int error)
107 {
108         _enter("%p,%p,%p,%d", cookie_data, page, data, error);
109
110         if (error)
111                 SetPageError(page);
112         else
113                 SetPageUptodate(page);
114         unlock_page(page);
115
116 }
117 #endif
118
119 /*
120  * deal with notification that a page was written to the cache
121  */
122 #ifdef AFS_CACHING_SUPPORT
123 static void afs_readpage_write_complete(void *cookie_data,
124                                         struct page *page,
125                                         void *data,
126                                         int error)
127 {
128         _enter("%p,%p,%p,%d", cookie_data, page, data, error);
129
130         unlock_page(page);
131 }
132 #endif
133
134 /*
135  * AFS read page from file, directory or symlink
136  */
137 static int afs_readpage(struct file *file, struct page *page)
138 {
139         struct afs_vnode *vnode;
140         struct inode *inode;
141         struct key *key;
142         size_t len;
143         off_t offset;
144         int ret;
145
146         inode = page->mapping->host;
147
148         ASSERT(file != NULL);
149         key = file->private_data;
150         ASSERT(key != NULL);
151
152         _enter("{%x},{%lu},{%lu}", key_serial(key), inode->i_ino, page->index);
153
154         vnode = AFS_FS_I(inode);
155
156         BUG_ON(!PageLocked(page));
157
158         ret = -ESTALE;
159         if (test_bit(AFS_VNODE_DELETED, &vnode->flags))
160                 goto error;
161
162 #ifdef AFS_CACHING_SUPPORT
163         /* is it cached? */
164         ret = cachefs_read_or_alloc_page(vnode->cache,
165                                          page,
166                                          afs_file_readpage_read_complete,
167                                          NULL,
168                                          GFP_KERNEL);
169 #else
170         ret = -ENOBUFS;
171 #endif
172
173         switch (ret) {
174                 /* read BIO submitted and wb-journal entry found */
175         case 1:
176                 BUG(); // TODO - handle wb-journal match
177
178                 /* read BIO submitted (page in cache) */
179         case 0:
180                 break;
181
182                 /* no page available in cache */
183         case -ENOBUFS:
184         case -ENODATA:
185         default:
186                 offset = page->index << PAGE_CACHE_SHIFT;
187                 len = min_t(size_t, i_size_read(inode) - offset, PAGE_SIZE);
188
189                 /* read the contents of the file from the server into the
190                  * page */
191                 ret = afs_vnode_fetch_data(vnode, key, offset, len, page);
192                 if (ret < 0) {
193                         if (ret == -ENOENT) {
194                                 _debug("got NOENT from server"
195                                        " - marking file deleted and stale");
196                                 set_bit(AFS_VNODE_DELETED, &vnode->flags);
197                                 ret = -ESTALE;
198                         }
199 #ifdef AFS_CACHING_SUPPORT
200                         cachefs_uncache_page(vnode->cache, page);
201 #endif
202                         goto error;
203                 }
204
205                 SetPageUptodate(page);
206
207 #ifdef AFS_CACHING_SUPPORT
208                 if (cachefs_write_page(vnode->cache,
209                                        page,
210                                        afs_file_readpage_write_complete,
211                                        NULL,
212                                        GFP_KERNEL) != 0
213                     ) {
214                         cachefs_uncache_page(vnode->cache, page);
215                         unlock_page(page);
216                 }
217 #else
218                 unlock_page(page);
219 #endif
220         }
221
222         _leave(" = 0");
223         return 0;
224
225 error:
226         SetPageError(page);
227         unlock_page(page);
228         _leave(" = %d", ret);
229         return ret;
230 }
231
232 /*
233  * invalidate part or all of a page
234  */
235 static void afs_invalidatepage(struct page *page, unsigned long offset)
236 {
237         int ret = 1;
238
239         _enter("{%lu},%lu", page->index, offset);
240
241         BUG_ON(!PageLocked(page));
242
243         if (PagePrivate(page)) {
244                 /* We release buffers only if the entire page is being
245                  * invalidated.
246                  * The get_block cached value has been unconditionally
247                  * invalidated, so real IO is not possible anymore.
248                  */
249                 if (offset == 0) {
250                         BUG_ON(!PageLocked(page));
251
252                         ret = 0;
253                         if (!PageWriteback(page))
254                                 ret = page->mapping->a_ops->releasepage(page,
255                                                                         0);
256                         /* possibly should BUG_ON(!ret); - neilb */
257                 }
258         }
259
260         _leave(" = %d", ret);
261 }
262
263 /*
264  * write back a dirty page
265  */
266 static int afs_launder_page(struct page *page)
267 {
268         _enter("{%lu}", page->index);
269
270         return 0;
271 }
272
273 /*
274  * release a page and cleanup its private data
275  */
276 static int afs_releasepage(struct page *page, gfp_t gfp_flags)
277 {
278         struct afs_vnode *vnode = AFS_FS_I(page->mapping->host);
279         struct afs_writeback *wb;
280
281         _enter("{{%x:%u}[%lu],%lx},%x",
282                vnode->fid.vid, vnode->fid.vnode, page->index, page->flags,
283                gfp_flags);
284
285         if (PagePrivate(page)) {
286                 wb = (struct afs_writeback *) page_private(page);
287                 ASSERT(wb != NULL);
288                 set_page_private(page, 0);
289                 ClearPagePrivate(page);
290                 afs_put_writeback(wb);
291         }
292
293         _leave(" = 0");
294         return 0;
295 }