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