xref: /openbmc/linux/fs/afs/file.c (revision d47992f86b307985b3215bcf141d56d1849d71df)
108e0e7c8SDavid Howells /* AFS filesystem file handling
21da177e4SLinus Torvalds  *
308e0e7c8SDavid Howells  * Copyright (C) 2002, 2007 Red Hat, Inc. All Rights Reserved.
41da177e4SLinus Torvalds  * Written by David Howells (dhowells@redhat.com)
51da177e4SLinus Torvalds  *
61da177e4SLinus Torvalds  * This program is free software; you can redistribute it and/or
71da177e4SLinus Torvalds  * modify it under the terms of the GNU General Public License
81da177e4SLinus Torvalds  * as published by the Free Software Foundation; either version
91da177e4SLinus Torvalds  * 2 of the License, or (at your option) any later version.
101da177e4SLinus Torvalds  */
111da177e4SLinus Torvalds 
121da177e4SLinus Torvalds #include <linux/kernel.h>
131da177e4SLinus Torvalds #include <linux/module.h>
141da177e4SLinus Torvalds #include <linux/init.h>
151da177e4SLinus Torvalds #include <linux/fs.h>
161da177e4SLinus Torvalds #include <linux/pagemap.h>
1731143d5dSDavid Howells #include <linux/writeback.h>
185a0e3ad6STejun Heo #include <linux/gfp.h>
191da177e4SLinus Torvalds #include "internal.h"
201da177e4SLinus Torvalds 
21416351f2SDavid Howells static int afs_readpage(struct file *file, struct page *page);
22*d47992f8SLukas Czerner static void afs_invalidatepage(struct page *page, unsigned int offset,
23*d47992f8SLukas Czerner 			       unsigned int length);
24416351f2SDavid Howells static int afs_releasepage(struct page *page, gfp_t gfp_flags);
2531143d5dSDavid Howells static int afs_launder_page(struct page *page);
261da177e4SLinus Torvalds 
279b3f26c9SDavid Howells static int afs_readpages(struct file *filp, struct address_space *mapping,
289b3f26c9SDavid Howells 			 struct list_head *pages, unsigned nr_pages);
299b3f26c9SDavid Howells 
3000d3b7a4SDavid Howells const struct file_operations afs_file_operations = {
3100d3b7a4SDavid Howells 	.open		= afs_open,
3200d3b7a4SDavid Howells 	.release	= afs_release,
3300d3b7a4SDavid Howells 	.llseek		= generic_file_llseek,
3400d3b7a4SDavid Howells 	.read		= do_sync_read,
3531143d5dSDavid Howells 	.write		= do_sync_write,
3600d3b7a4SDavid Howells 	.aio_read	= generic_file_aio_read,
3731143d5dSDavid Howells 	.aio_write	= afs_file_write,
3800d3b7a4SDavid Howells 	.mmap		= generic_file_readonly_mmap,
395ffc4ef4SJens Axboe 	.splice_read	= generic_file_splice_read,
4031143d5dSDavid Howells 	.fsync		= afs_fsync,
41e8d6c554SDavid Howells 	.lock		= afs_lock,
42e8d6c554SDavid Howells 	.flock		= afs_flock,
4300d3b7a4SDavid Howells };
4400d3b7a4SDavid Howells 
45754661f1SArjan van de Ven const struct inode_operations afs_file_inode_operations = {
46416351f2SDavid Howells 	.getattr	= afs_getattr,
4731143d5dSDavid Howells 	.setattr	= afs_setattr,
4800d3b7a4SDavid Howells 	.permission	= afs_permission,
491da177e4SLinus Torvalds };
501da177e4SLinus Torvalds 
51f5e54d6eSChristoph Hellwig const struct address_space_operations afs_fs_aops = {
52416351f2SDavid Howells 	.readpage	= afs_readpage,
539b3f26c9SDavid Howells 	.readpages	= afs_readpages,
5431143d5dSDavid Howells 	.set_page_dirty	= afs_set_page_dirty,
5531143d5dSDavid Howells 	.launder_page	= afs_launder_page,
56416351f2SDavid Howells 	.releasepage	= afs_releasepage,
57416351f2SDavid Howells 	.invalidatepage	= afs_invalidatepage,
5815b4650eSNick Piggin 	.write_begin	= afs_write_begin,
5915b4650eSNick Piggin 	.write_end	= afs_write_end,
6031143d5dSDavid Howells 	.writepage	= afs_writepage,
6131143d5dSDavid Howells 	.writepages	= afs_writepages,
621da177e4SLinus Torvalds };
631da177e4SLinus Torvalds 
641da177e4SLinus Torvalds /*
6500d3b7a4SDavid Howells  * open an AFS file or directory and attach a key to it
6600d3b7a4SDavid Howells  */
6700d3b7a4SDavid Howells int afs_open(struct inode *inode, struct file *file)
6800d3b7a4SDavid Howells {
6900d3b7a4SDavid Howells 	struct afs_vnode *vnode = AFS_FS_I(inode);
7000d3b7a4SDavid Howells 	struct key *key;
71260a9803SDavid Howells 	int ret;
7200d3b7a4SDavid Howells 
73416351f2SDavid Howells 	_enter("{%x:%u},", vnode->fid.vid, vnode->fid.vnode);
7400d3b7a4SDavid Howells 
7500d3b7a4SDavid Howells 	key = afs_request_key(vnode->volume->cell);
7600d3b7a4SDavid Howells 	if (IS_ERR(key)) {
7700d3b7a4SDavid Howells 		_leave(" = %ld [key]", PTR_ERR(key));
7800d3b7a4SDavid Howells 		return PTR_ERR(key);
7900d3b7a4SDavid Howells 	}
8000d3b7a4SDavid Howells 
81260a9803SDavid Howells 	ret = afs_validate(vnode, key);
82260a9803SDavid Howells 	if (ret < 0) {
83260a9803SDavid Howells 		_leave(" = %d [val]", ret);
84260a9803SDavid Howells 		return ret;
85260a9803SDavid Howells 	}
86260a9803SDavid Howells 
8700d3b7a4SDavid Howells 	file->private_data = key;
8800d3b7a4SDavid Howells 	_leave(" = 0");
8900d3b7a4SDavid Howells 	return 0;
9000d3b7a4SDavid Howells }
9100d3b7a4SDavid Howells 
9200d3b7a4SDavid Howells /*
9300d3b7a4SDavid Howells  * release an AFS file or directory and discard its key
9400d3b7a4SDavid Howells  */
9500d3b7a4SDavid Howells int afs_release(struct inode *inode, struct file *file)
9600d3b7a4SDavid Howells {
9700d3b7a4SDavid Howells 	struct afs_vnode *vnode = AFS_FS_I(inode);
9800d3b7a4SDavid Howells 
99416351f2SDavid Howells 	_enter("{%x:%u},", vnode->fid.vid, vnode->fid.vnode);
10000d3b7a4SDavid Howells 
10100d3b7a4SDavid Howells 	key_put(file->private_data);
10200d3b7a4SDavid Howells 	_leave(" = 0");
10300d3b7a4SDavid Howells 	return 0;
10400d3b7a4SDavid Howells }
10500d3b7a4SDavid Howells 
1066566abdbSMatt Kraai #ifdef CONFIG_AFS_FSCACHE
10700d3b7a4SDavid Howells /*
1081da177e4SLinus Torvalds  * deal with notification that a page was read from the cache
1091da177e4SLinus Torvalds  */
1109b3f26c9SDavid Howells static void afs_file_readpage_read_complete(struct page *page,
1111da177e4SLinus Torvalds 					    void *data,
1121da177e4SLinus Torvalds 					    int error)
1131da177e4SLinus Torvalds {
1149b3f26c9SDavid Howells 	_enter("%p,%p,%d", page, data, error);
1151da177e4SLinus Torvalds 
1169b3f26c9SDavid Howells 	/* if the read completes with an error, we just unlock the page and let
1179b3f26c9SDavid Howells 	 * the VM reissue the readpage */
1189b3f26c9SDavid Howells 	if (!error)
1191da177e4SLinus Torvalds 		SetPageUptodate(page);
1201da177e4SLinus Torvalds 	unlock_page(page);
121ec26815aSDavid Howells }
1226566abdbSMatt Kraai #endif
1231da177e4SLinus Torvalds 
1241da177e4SLinus Torvalds /*
125f6d335c0SAl Viro  * read page from file, directory or symlink, given a key to use
1261da177e4SLinus Torvalds  */
127f6d335c0SAl Viro int afs_page_filler(void *data, struct page *page)
1281da177e4SLinus Torvalds {
129f6d335c0SAl Viro 	struct inode *inode = page->mapping->host;
130f6d335c0SAl Viro 	struct afs_vnode *vnode = AFS_FS_I(inode);
131f6d335c0SAl Viro 	struct key *key = data;
13208e0e7c8SDavid Howells 	size_t len;
13308e0e7c8SDavid Howells 	off_t offset;
1341da177e4SLinus Torvalds 	int ret;
1351da177e4SLinus Torvalds 
13600d3b7a4SDavid Howells 	_enter("{%x},{%lu},{%lu}", key_serial(key), inode->i_ino, page->index);
1371da177e4SLinus Torvalds 
138cd7619d6SMatt Mackall 	BUG_ON(!PageLocked(page));
1391da177e4SLinus Torvalds 
1401da177e4SLinus Torvalds 	ret = -ESTALE;
14108e0e7c8SDavid Howells 	if (test_bit(AFS_VNODE_DELETED, &vnode->flags))
1421da177e4SLinus Torvalds 		goto error;
1431da177e4SLinus Torvalds 
1441da177e4SLinus Torvalds 	/* is it cached? */
1459b3f26c9SDavid Howells #ifdef CONFIG_AFS_FSCACHE
1469b3f26c9SDavid Howells 	ret = fscache_read_or_alloc_page(vnode->cache,
1471da177e4SLinus Torvalds 					 page,
1481da177e4SLinus Torvalds 					 afs_file_readpage_read_complete,
1491da177e4SLinus Torvalds 					 NULL,
1501da177e4SLinus Torvalds 					 GFP_KERNEL);
1511da177e4SLinus Torvalds #else
1521da177e4SLinus Torvalds 	ret = -ENOBUFS;
1531da177e4SLinus Torvalds #endif
1541da177e4SLinus Torvalds 	switch (ret) {
1551da177e4SLinus Torvalds 		/* read BIO submitted (page in cache) */
1561da177e4SLinus Torvalds 	case 0:
1571da177e4SLinus Torvalds 		break;
1581da177e4SLinus Torvalds 
1599b3f26c9SDavid Howells 		/* page not yet cached */
1601da177e4SLinus Torvalds 	case -ENODATA:
1619b3f26c9SDavid Howells 		_debug("cache said ENODATA");
1629b3f26c9SDavid Howells 		goto go_on;
1639b3f26c9SDavid Howells 
1649b3f26c9SDavid Howells 		/* page will not be cached */
1659b3f26c9SDavid Howells 	case -ENOBUFS:
1669b3f26c9SDavid Howells 		_debug("cache said ENOBUFS");
1671da177e4SLinus Torvalds 	default:
1689b3f26c9SDavid Howells 	go_on:
16908e0e7c8SDavid Howells 		offset = page->index << PAGE_CACHE_SHIFT;
17008e0e7c8SDavid Howells 		len = min_t(size_t, i_size_read(inode) - offset, PAGE_SIZE);
1711da177e4SLinus Torvalds 
1721da177e4SLinus Torvalds 		/* read the contents of the file from the server into the
1731da177e4SLinus Torvalds 		 * page */
17400d3b7a4SDavid Howells 		ret = afs_vnode_fetch_data(vnode, key, offset, len, page);
1751da177e4SLinus Torvalds 		if (ret < 0) {
1761da177e4SLinus Torvalds 			if (ret == -ENOENT) {
1771da177e4SLinus Torvalds 				_debug("got NOENT from server"
1781da177e4SLinus Torvalds 				       " - marking file deleted and stale");
17908e0e7c8SDavid Howells 				set_bit(AFS_VNODE_DELETED, &vnode->flags);
1801da177e4SLinus Torvalds 				ret = -ESTALE;
1811da177e4SLinus Torvalds 			}
1829b3f26c9SDavid Howells 
1839b3f26c9SDavid Howells #ifdef CONFIG_AFS_FSCACHE
1849b3f26c9SDavid Howells 			fscache_uncache_page(vnode->cache, page);
1851da177e4SLinus Torvalds #endif
1869b3f26c9SDavid Howells 			BUG_ON(PageFsCache(page));
1871da177e4SLinus Torvalds 			goto error;
1881da177e4SLinus Torvalds 		}
1891da177e4SLinus Torvalds 
1901da177e4SLinus Torvalds 		SetPageUptodate(page);
1911da177e4SLinus Torvalds 
1929b3f26c9SDavid Howells 		/* send the page to the cache */
1939b3f26c9SDavid Howells #ifdef CONFIG_AFS_FSCACHE
1949b3f26c9SDavid Howells 		if (PageFsCache(page) &&
1959b3f26c9SDavid Howells 		    fscache_write_page(vnode->cache, page, GFP_KERNEL) != 0) {
1969b3f26c9SDavid Howells 			fscache_uncache_page(vnode->cache, page);
1979b3f26c9SDavid Howells 			BUG_ON(PageFsCache(page));
1981da177e4SLinus Torvalds 		}
1991da177e4SLinus Torvalds #endif
2009b3f26c9SDavid Howells 		unlock_page(page);
2011da177e4SLinus Torvalds 	}
2021da177e4SLinus Torvalds 
2031da177e4SLinus Torvalds 	_leave(" = 0");
2041da177e4SLinus Torvalds 	return 0;
2051da177e4SLinus Torvalds 
2061da177e4SLinus Torvalds error:
2071da177e4SLinus Torvalds 	SetPageError(page);
2081da177e4SLinus Torvalds 	unlock_page(page);
2091da177e4SLinus Torvalds 	_leave(" = %d", ret);
2101da177e4SLinus Torvalds 	return ret;
211ec26815aSDavid Howells }
2121da177e4SLinus Torvalds 
2131da177e4SLinus Torvalds /*
214f6d335c0SAl Viro  * read page from file, directory or symlink, given a file to nominate the key
215f6d335c0SAl Viro  * to be used
216f6d335c0SAl Viro  */
217f6d335c0SAl Viro static int afs_readpage(struct file *file, struct page *page)
218f6d335c0SAl Viro {
219f6d335c0SAl Viro 	struct key *key;
220f6d335c0SAl Viro 	int ret;
221f6d335c0SAl Viro 
222f6d335c0SAl Viro 	if (file) {
223f6d335c0SAl Viro 		key = file->private_data;
224f6d335c0SAl Viro 		ASSERT(key != NULL);
225f6d335c0SAl Viro 		ret = afs_page_filler(key, page);
226f6d335c0SAl Viro 	} else {
227f6d335c0SAl Viro 		struct inode *inode = page->mapping->host;
228f6d335c0SAl Viro 		key = afs_request_key(AFS_FS_S(inode->i_sb)->volume->cell);
229f6d335c0SAl Viro 		if (IS_ERR(key)) {
230f6d335c0SAl Viro 			ret = PTR_ERR(key);
231f6d335c0SAl Viro 		} else {
232f6d335c0SAl Viro 			ret = afs_page_filler(key, page);
233f6d335c0SAl Viro 			key_put(key);
234f6d335c0SAl Viro 		}
235f6d335c0SAl Viro 	}
236f6d335c0SAl Viro 	return ret;
237f6d335c0SAl Viro }
238f6d335c0SAl Viro 
239f6d335c0SAl Viro /*
2409b3f26c9SDavid Howells  * read a set of pages
2411da177e4SLinus Torvalds  */
2429b3f26c9SDavid Howells static int afs_readpages(struct file *file, struct address_space *mapping,
2439b3f26c9SDavid Howells 			 struct list_head *pages, unsigned nr_pages)
2441da177e4SLinus Torvalds {
245f6d335c0SAl Viro 	struct key *key = file->private_data;
2469b3f26c9SDavid Howells 	struct afs_vnode *vnode;
2479b3f26c9SDavid Howells 	int ret = 0;
2481da177e4SLinus Torvalds 
249f6d335c0SAl Viro 	_enter("{%d},{%lu},,%d",
250f6d335c0SAl Viro 	       key_serial(key), mapping->host->i_ino, nr_pages);
251f6d335c0SAl Viro 
252f6d335c0SAl Viro 	ASSERT(key != NULL);
2531da177e4SLinus Torvalds 
2549b3f26c9SDavid Howells 	vnode = AFS_FS_I(mapping->host);
255ad2a8e60SDan Carpenter 	if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) {
2569b3f26c9SDavid Howells 		_leave(" = -ESTALE");
2579b3f26c9SDavid Howells 		return -ESTALE;
2581da177e4SLinus Torvalds 	}
2591da177e4SLinus Torvalds 
2609b3f26c9SDavid Howells 	/* attempt to read as many of the pages as possible */
2619b3f26c9SDavid Howells #ifdef CONFIG_AFS_FSCACHE
2629b3f26c9SDavid Howells 	ret = fscache_read_or_alloc_pages(vnode->cache,
2639b3f26c9SDavid Howells 					  mapping,
2649b3f26c9SDavid Howells 					  pages,
2659b3f26c9SDavid Howells 					  &nr_pages,
2669b3f26c9SDavid Howells 					  afs_file_readpage_read_complete,
2679b3f26c9SDavid Howells 					  NULL,
2689b3f26c9SDavid Howells 					  mapping_gfp_mask(mapping));
2699b3f26c9SDavid Howells #else
2709b3f26c9SDavid Howells 	ret = -ENOBUFS;
2719b3f26c9SDavid Howells #endif
2729b3f26c9SDavid Howells 
2739b3f26c9SDavid Howells 	switch (ret) {
2749b3f26c9SDavid Howells 		/* all pages are being read from the cache */
2759b3f26c9SDavid Howells 	case 0:
2769b3f26c9SDavid Howells 		BUG_ON(!list_empty(pages));
2779b3f26c9SDavid Howells 		BUG_ON(nr_pages != 0);
2789b3f26c9SDavid Howells 		_leave(" = 0 [reading all]");
2799b3f26c9SDavid Howells 		return 0;
2809b3f26c9SDavid Howells 
2819b3f26c9SDavid Howells 		/* there were pages that couldn't be read from the cache */
2829b3f26c9SDavid Howells 	case -ENODATA:
2839b3f26c9SDavid Howells 	case -ENOBUFS:
2849b3f26c9SDavid Howells 		break;
2859b3f26c9SDavid Howells 
2869b3f26c9SDavid Howells 		/* other error */
2879b3f26c9SDavid Howells 	default:
2881da177e4SLinus Torvalds 		_leave(" = %d", ret);
2899b3f26c9SDavid Howells 		return ret;
2909b3f26c9SDavid Howells 	}
2919b3f26c9SDavid Howells 
2929b3f26c9SDavid Howells 	/* load the missing pages from the network */
293f6d335c0SAl Viro 	ret = read_cache_pages(mapping, pages, afs_page_filler, key);
2949b3f26c9SDavid Howells 
2959b3f26c9SDavid Howells 	_leave(" = %d [netting]", ret);
2969b3f26c9SDavid Howells 	return ret;
297ec26815aSDavid Howells }
2981da177e4SLinus Torvalds 
2991da177e4SLinus Torvalds /*
30031143d5dSDavid Howells  * write back a dirty page
30131143d5dSDavid Howells  */
30231143d5dSDavid Howells static int afs_launder_page(struct page *page)
30331143d5dSDavid Howells {
30431143d5dSDavid Howells 	_enter("{%lu}", page->index);
30531143d5dSDavid Howells 
30631143d5dSDavid Howells 	return 0;
30731143d5dSDavid Howells }
30831143d5dSDavid Howells 
30931143d5dSDavid Howells /*
3109b3f26c9SDavid Howells  * invalidate part or all of a page
3119b3f26c9SDavid Howells  * - release a page and clean up its private data if offset is 0 (indicating
3129b3f26c9SDavid Howells  *   the entire page)
3139b3f26c9SDavid Howells  */
314*d47992f8SLukas Czerner static void afs_invalidatepage(struct page *page, unsigned int offset,
315*d47992f8SLukas Czerner 			       unsigned int length)
3169b3f26c9SDavid Howells {
3179b3f26c9SDavid Howells 	struct afs_writeback *wb = (struct afs_writeback *) page_private(page);
3189b3f26c9SDavid Howells 
319*d47992f8SLukas Czerner 	_enter("{%lu},%u,%u", page->index, offset, length);
3209b3f26c9SDavid Howells 
3219b3f26c9SDavid Howells 	BUG_ON(!PageLocked(page));
3229b3f26c9SDavid Howells 
3239b3f26c9SDavid Howells 	/* we clean up only if the entire page is being invalidated */
324*d47992f8SLukas Czerner 	if (offset == 0 && length == PAGE_CACHE_SIZE) {
3259b3f26c9SDavid Howells #ifdef CONFIG_AFS_FSCACHE
3269b3f26c9SDavid Howells 		if (PageFsCache(page)) {
3279b3f26c9SDavid Howells 			struct afs_vnode *vnode = AFS_FS_I(page->mapping->host);
3289b3f26c9SDavid Howells 			fscache_wait_on_page_write(vnode->cache, page);
3299b3f26c9SDavid Howells 			fscache_uncache_page(vnode->cache, page);
3309b3f26c9SDavid Howells 		}
3319b3f26c9SDavid Howells #endif
3329b3f26c9SDavid Howells 
3339b3f26c9SDavid Howells 		if (PagePrivate(page)) {
3349b3f26c9SDavid Howells 			if (wb && !PageWriteback(page)) {
3359b3f26c9SDavid Howells 				set_page_private(page, 0);
3369b3f26c9SDavid Howells 				afs_put_writeback(wb);
3379b3f26c9SDavid Howells 			}
3389b3f26c9SDavid Howells 
3399b3f26c9SDavid Howells 			if (!page_private(page))
3409b3f26c9SDavid Howells 				ClearPagePrivate(page);
3419b3f26c9SDavid Howells 		}
3429b3f26c9SDavid Howells 	}
3439b3f26c9SDavid Howells 
3449b3f26c9SDavid Howells 	_leave("");
3459b3f26c9SDavid Howells }
3469b3f26c9SDavid Howells 
3479b3f26c9SDavid Howells /*
3489b3f26c9SDavid Howells  * release a page and clean up its private state if it's not busy
3499b3f26c9SDavid Howells  * - return true if the page can now be released, false if not
3501da177e4SLinus Torvalds  */
351416351f2SDavid Howells static int afs_releasepage(struct page *page, gfp_t gfp_flags)
3521da177e4SLinus Torvalds {
3539b3f26c9SDavid Howells 	struct afs_writeback *wb = (struct afs_writeback *) page_private(page);
354416351f2SDavid Howells 	struct afs_vnode *vnode = AFS_FS_I(page->mapping->host);
3551da177e4SLinus Torvalds 
356416351f2SDavid Howells 	_enter("{{%x:%u}[%lu],%lx},%x",
357416351f2SDavid Howells 	       vnode->fid.vid, vnode->fid.vnode, page->index, page->flags,
358416351f2SDavid Howells 	       gfp_flags);
3591da177e4SLinus Torvalds 
3609b3f26c9SDavid Howells 	/* deny if page is being written to the cache and the caller hasn't
3619b3f26c9SDavid Howells 	 * elected to wait */
3629b3f26c9SDavid Howells #ifdef CONFIG_AFS_FSCACHE
363201a1542SDavid Howells 	if (!fscache_maybe_release_page(vnode->cache, page, gfp_flags)) {
3649b3f26c9SDavid Howells 		_leave(" = F [cache busy]");
3659b3f26c9SDavid Howells 		return 0;
3669b3f26c9SDavid Howells 	}
3679b3f26c9SDavid Howells #endif
3689b3f26c9SDavid Howells 
3699b3f26c9SDavid Howells 	if (PagePrivate(page)) {
3709b3f26c9SDavid Howells 		if (wb) {
3719b3f26c9SDavid Howells 			set_page_private(page, 0);
3729b3f26c9SDavid Howells 			afs_put_writeback(wb);
3739b3f26c9SDavid Howells 		}
3749b3f26c9SDavid Howells 		ClearPagePrivate(page);
3759b3f26c9SDavid Howells 	}
3769b3f26c9SDavid Howells 
3779b3f26c9SDavid Howells 	/* indicate that the page can be released */
3789b3f26c9SDavid Howells 	_leave(" = T");
3799b3f26c9SDavid Howells 	return 1;
380ec26815aSDavid Howells }
381