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
21static int afs_readpage(struct file *file, struct page *page);
22static void afs_invalidatepage(struct page *page, unsigned long offset);
23static int afs_releasepage(struct page *page, gfp_t gfp_flags);
24static int afs_launder_page(struct page *page);
25
26const 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
39const struct inode_operations afs_file_inode_operations = {
40	.getattr	= afs_getattr,
41	.setattr	= afs_setattr,
42	.permission	= afs_permission,
43};
44
45const 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 */
60int 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 */
88int 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
103static 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
123static 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 */
137static 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
225error:
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 */
235static 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 */
266static 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 */
276static 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}
296