xref: /openbmc/linux/fs/afs/file.c (revision 196ee9cd2d04728d0ec0038a2856b86142615b11)
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);
22d47992f8SLukas Czerner static void afs_invalidatepage(struct page *page, unsigned int offset,
23d47992f8SLukas 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,
34aad4f8bbSAl Viro 	.read_iter	= generic_file_read_iter,
3550b5551dSAl Viro 	.write_iter	= afs_file_write,
3600d3b7a4SDavid Howells 	.mmap		= generic_file_readonly_mmap,
375ffc4ef4SJens Axboe 	.splice_read	= generic_file_splice_read,
3831143d5dSDavid Howells 	.fsync		= afs_fsync,
39e8d6c554SDavid Howells 	.lock		= afs_lock,
40e8d6c554SDavid Howells 	.flock		= afs_flock,
4100d3b7a4SDavid Howells };
4200d3b7a4SDavid Howells 
43754661f1SArjan van de Ven const struct inode_operations afs_file_inode_operations = {
44416351f2SDavid Howells 	.getattr	= afs_getattr,
4531143d5dSDavid Howells 	.setattr	= afs_setattr,
4600d3b7a4SDavid Howells 	.permission	= afs_permission,
471da177e4SLinus Torvalds };
481da177e4SLinus Torvalds 
49f5e54d6eSChristoph Hellwig const struct address_space_operations afs_fs_aops = {
50416351f2SDavid Howells 	.readpage	= afs_readpage,
519b3f26c9SDavid Howells 	.readpages	= afs_readpages,
5231143d5dSDavid Howells 	.set_page_dirty	= afs_set_page_dirty,
5331143d5dSDavid Howells 	.launder_page	= afs_launder_page,
54416351f2SDavid Howells 	.releasepage	= afs_releasepage,
55416351f2SDavid Howells 	.invalidatepage	= afs_invalidatepage,
5615b4650eSNick Piggin 	.write_begin	= afs_write_begin,
5715b4650eSNick Piggin 	.write_end	= afs_write_end,
5831143d5dSDavid Howells 	.writepage	= afs_writepage,
5931143d5dSDavid Howells 	.writepages	= afs_writepages,
601da177e4SLinus Torvalds };
611da177e4SLinus Torvalds 
621da177e4SLinus Torvalds /*
6300d3b7a4SDavid Howells  * open an AFS file or directory and attach a key to it
6400d3b7a4SDavid Howells  */
6500d3b7a4SDavid Howells int afs_open(struct inode *inode, struct file *file)
6600d3b7a4SDavid Howells {
6700d3b7a4SDavid Howells 	struct afs_vnode *vnode = AFS_FS_I(inode);
6800d3b7a4SDavid Howells 	struct key *key;
69260a9803SDavid Howells 	int ret;
7000d3b7a4SDavid Howells 
71416351f2SDavid Howells 	_enter("{%x:%u},", vnode->fid.vid, vnode->fid.vnode);
7200d3b7a4SDavid Howells 
7300d3b7a4SDavid Howells 	key = afs_request_key(vnode->volume->cell);
7400d3b7a4SDavid Howells 	if (IS_ERR(key)) {
7500d3b7a4SDavid Howells 		_leave(" = %ld [key]", PTR_ERR(key));
7600d3b7a4SDavid Howells 		return PTR_ERR(key);
7700d3b7a4SDavid Howells 	}
7800d3b7a4SDavid Howells 
79260a9803SDavid Howells 	ret = afs_validate(vnode, key);
80260a9803SDavid Howells 	if (ret < 0) {
81260a9803SDavid Howells 		_leave(" = %d [val]", ret);
82260a9803SDavid Howells 		return ret;
83260a9803SDavid Howells 	}
84260a9803SDavid Howells 
8500d3b7a4SDavid Howells 	file->private_data = key;
8600d3b7a4SDavid Howells 	_leave(" = 0");
8700d3b7a4SDavid Howells 	return 0;
8800d3b7a4SDavid Howells }
8900d3b7a4SDavid Howells 
9000d3b7a4SDavid Howells /*
9100d3b7a4SDavid Howells  * release an AFS file or directory and discard its key
9200d3b7a4SDavid Howells  */
9300d3b7a4SDavid Howells int afs_release(struct inode *inode, struct file *file)
9400d3b7a4SDavid Howells {
9500d3b7a4SDavid Howells 	struct afs_vnode *vnode = AFS_FS_I(inode);
9600d3b7a4SDavid Howells 
97416351f2SDavid Howells 	_enter("{%x:%u},", vnode->fid.vid, vnode->fid.vnode);
9800d3b7a4SDavid Howells 
9900d3b7a4SDavid Howells 	key_put(file->private_data);
10000d3b7a4SDavid Howells 	_leave(" = 0");
10100d3b7a4SDavid Howells 	return 0;
10200d3b7a4SDavid Howells }
10300d3b7a4SDavid Howells 
104*196ee9cdSDavid Howells /*
105*196ee9cdSDavid Howells  * Dispose of a ref to a read record.
106*196ee9cdSDavid Howells  */
107*196ee9cdSDavid Howells void afs_put_read(struct afs_read *req)
108*196ee9cdSDavid Howells {
109*196ee9cdSDavid Howells 	int i;
110*196ee9cdSDavid Howells 
111*196ee9cdSDavid Howells 	if (atomic_dec_and_test(&req->usage)) {
112*196ee9cdSDavid Howells 		for (i = 0; i < req->nr_pages; i++)
113*196ee9cdSDavid Howells 			if (req->pages[i])
114*196ee9cdSDavid Howells 				put_page(req->pages[i]);
115*196ee9cdSDavid Howells 		kfree(req);
116*196ee9cdSDavid Howells 	}
117*196ee9cdSDavid Howells }
118*196ee9cdSDavid Howells 
1196566abdbSMatt Kraai #ifdef CONFIG_AFS_FSCACHE
12000d3b7a4SDavid Howells /*
1211da177e4SLinus Torvalds  * deal with notification that a page was read from the cache
1221da177e4SLinus Torvalds  */
1239b3f26c9SDavid Howells static void afs_file_readpage_read_complete(struct page *page,
1241da177e4SLinus Torvalds 					    void *data,
1251da177e4SLinus Torvalds 					    int error)
1261da177e4SLinus Torvalds {
1279b3f26c9SDavid Howells 	_enter("%p,%p,%d", page, data, error);
1281da177e4SLinus Torvalds 
1299b3f26c9SDavid Howells 	/* if the read completes with an error, we just unlock the page and let
1309b3f26c9SDavid Howells 	 * the VM reissue the readpage */
1319b3f26c9SDavid Howells 	if (!error)
1321da177e4SLinus Torvalds 		SetPageUptodate(page);
1331da177e4SLinus Torvalds 	unlock_page(page);
134ec26815aSDavid Howells }
1356566abdbSMatt Kraai #endif
1361da177e4SLinus Torvalds 
1371da177e4SLinus Torvalds /*
138f6d335c0SAl Viro  * read page from file, directory or symlink, given a key to use
1391da177e4SLinus Torvalds  */
140f6d335c0SAl Viro int afs_page_filler(void *data, struct page *page)
1411da177e4SLinus Torvalds {
142f6d335c0SAl Viro 	struct inode *inode = page->mapping->host;
143f6d335c0SAl Viro 	struct afs_vnode *vnode = AFS_FS_I(inode);
144*196ee9cdSDavid Howells 	struct afs_read *req;
145f6d335c0SAl Viro 	struct key *key = data;
1461da177e4SLinus Torvalds 	int ret;
1471da177e4SLinus Torvalds 
14800d3b7a4SDavid Howells 	_enter("{%x},{%lu},{%lu}", key_serial(key), inode->i_ino, page->index);
1491da177e4SLinus Torvalds 
150cd7619d6SMatt Mackall 	BUG_ON(!PageLocked(page));
1511da177e4SLinus Torvalds 
1521da177e4SLinus Torvalds 	ret = -ESTALE;
15308e0e7c8SDavid Howells 	if (test_bit(AFS_VNODE_DELETED, &vnode->flags))
1541da177e4SLinus Torvalds 		goto error;
1551da177e4SLinus Torvalds 
1561da177e4SLinus Torvalds 	/* is it cached? */
1579b3f26c9SDavid Howells #ifdef CONFIG_AFS_FSCACHE
1589b3f26c9SDavid Howells 	ret = fscache_read_or_alloc_page(vnode->cache,
1591da177e4SLinus Torvalds 					 page,
1601da177e4SLinus Torvalds 					 afs_file_readpage_read_complete,
1611da177e4SLinus Torvalds 					 NULL,
1621da177e4SLinus Torvalds 					 GFP_KERNEL);
1631da177e4SLinus Torvalds #else
1641da177e4SLinus Torvalds 	ret = -ENOBUFS;
1651da177e4SLinus Torvalds #endif
1661da177e4SLinus Torvalds 	switch (ret) {
1671da177e4SLinus Torvalds 		/* read BIO submitted (page in cache) */
1681da177e4SLinus Torvalds 	case 0:
1691da177e4SLinus Torvalds 		break;
1701da177e4SLinus Torvalds 
1719b3f26c9SDavid Howells 		/* page not yet cached */
1721da177e4SLinus Torvalds 	case -ENODATA:
1739b3f26c9SDavid Howells 		_debug("cache said ENODATA");
1749b3f26c9SDavid Howells 		goto go_on;
1759b3f26c9SDavid Howells 
1769b3f26c9SDavid Howells 		/* page will not be cached */
1779b3f26c9SDavid Howells 	case -ENOBUFS:
1789b3f26c9SDavid Howells 		_debug("cache said ENOBUFS");
1791da177e4SLinus Torvalds 	default:
1809b3f26c9SDavid Howells 	go_on:
181*196ee9cdSDavid Howells 		req = kzalloc(sizeof(struct afs_read) + sizeof(struct page *),
182*196ee9cdSDavid Howells 			      GFP_KERNEL);
183*196ee9cdSDavid Howells 		if (!req)
184*196ee9cdSDavid Howells 			goto enomem;
185*196ee9cdSDavid Howells 
186*196ee9cdSDavid Howells 		atomic_set(&req->usage, 1);
187*196ee9cdSDavid Howells 		req->pos = (loff_t)page->index << PAGE_SHIFT;
188*196ee9cdSDavid Howells 		req->len = min_t(size_t, i_size_read(inode) - req->pos,
189*196ee9cdSDavid Howells 				 PAGE_SIZE);
190*196ee9cdSDavid Howells 		req->nr_pages = 1;
191*196ee9cdSDavid Howells 		req->pages[0] = page;
192*196ee9cdSDavid Howells 		get_page(page);
1931da177e4SLinus Torvalds 
1941da177e4SLinus Torvalds 		/* read the contents of the file from the server into the
1951da177e4SLinus Torvalds 		 * page */
196*196ee9cdSDavid Howells 		ret = afs_vnode_fetch_data(vnode, key, req);
197*196ee9cdSDavid Howells 		afs_put_read(req);
1981da177e4SLinus Torvalds 		if (ret < 0) {
1991da177e4SLinus Torvalds 			if (ret == -ENOENT) {
2001da177e4SLinus Torvalds 				_debug("got NOENT from server"
2011da177e4SLinus Torvalds 				       " - marking file deleted and stale");
20208e0e7c8SDavid Howells 				set_bit(AFS_VNODE_DELETED, &vnode->flags);
2031da177e4SLinus Torvalds 				ret = -ESTALE;
2041da177e4SLinus Torvalds 			}
2059b3f26c9SDavid Howells 
2069b3f26c9SDavid Howells #ifdef CONFIG_AFS_FSCACHE
2079b3f26c9SDavid Howells 			fscache_uncache_page(vnode->cache, page);
2081da177e4SLinus Torvalds #endif
2099b3f26c9SDavid Howells 			BUG_ON(PageFsCache(page));
2101da177e4SLinus Torvalds 			goto error;
2111da177e4SLinus Torvalds 		}
2121da177e4SLinus Torvalds 
2131da177e4SLinus Torvalds 		SetPageUptodate(page);
2141da177e4SLinus Torvalds 
2159b3f26c9SDavid Howells 		/* send the page to the cache */
2169b3f26c9SDavid Howells #ifdef CONFIG_AFS_FSCACHE
2179b3f26c9SDavid Howells 		if (PageFsCache(page) &&
2189b3f26c9SDavid Howells 		    fscache_write_page(vnode->cache, page, GFP_KERNEL) != 0) {
2199b3f26c9SDavid Howells 			fscache_uncache_page(vnode->cache, page);
2209b3f26c9SDavid Howells 			BUG_ON(PageFsCache(page));
2211da177e4SLinus Torvalds 		}
2221da177e4SLinus Torvalds #endif
2239b3f26c9SDavid Howells 		unlock_page(page);
2241da177e4SLinus Torvalds 	}
2251da177e4SLinus Torvalds 
2261da177e4SLinus Torvalds 	_leave(" = 0");
2271da177e4SLinus Torvalds 	return 0;
2281da177e4SLinus Torvalds 
229*196ee9cdSDavid Howells enomem:
230*196ee9cdSDavid Howells 	ret = -ENOMEM;
2311da177e4SLinus Torvalds error:
2321da177e4SLinus Torvalds 	SetPageError(page);
2331da177e4SLinus Torvalds 	unlock_page(page);
2341da177e4SLinus Torvalds 	_leave(" = %d", ret);
2351da177e4SLinus Torvalds 	return ret;
236ec26815aSDavid Howells }
2371da177e4SLinus Torvalds 
2381da177e4SLinus Torvalds /*
239f6d335c0SAl Viro  * read page from file, directory or symlink, given a file to nominate the key
240f6d335c0SAl Viro  * to be used
241f6d335c0SAl Viro  */
242f6d335c0SAl Viro static int afs_readpage(struct file *file, struct page *page)
243f6d335c0SAl Viro {
244f6d335c0SAl Viro 	struct key *key;
245f6d335c0SAl Viro 	int ret;
246f6d335c0SAl Viro 
247f6d335c0SAl Viro 	if (file) {
248f6d335c0SAl Viro 		key = file->private_data;
249f6d335c0SAl Viro 		ASSERT(key != NULL);
250f6d335c0SAl Viro 		ret = afs_page_filler(key, page);
251f6d335c0SAl Viro 	} else {
252f6d335c0SAl Viro 		struct inode *inode = page->mapping->host;
253f6d335c0SAl Viro 		key = afs_request_key(AFS_FS_S(inode->i_sb)->volume->cell);
254f6d335c0SAl Viro 		if (IS_ERR(key)) {
255f6d335c0SAl Viro 			ret = PTR_ERR(key);
256f6d335c0SAl Viro 		} else {
257f6d335c0SAl Viro 			ret = afs_page_filler(key, page);
258f6d335c0SAl Viro 			key_put(key);
259f6d335c0SAl Viro 		}
260f6d335c0SAl Viro 	}
261f6d335c0SAl Viro 	return ret;
262f6d335c0SAl Viro }
263f6d335c0SAl Viro 
264f6d335c0SAl Viro /*
2659b3f26c9SDavid Howells  * read a set of pages
2661da177e4SLinus Torvalds  */
2679b3f26c9SDavid Howells static int afs_readpages(struct file *file, struct address_space *mapping,
2689b3f26c9SDavid Howells 			 struct list_head *pages, unsigned nr_pages)
2691da177e4SLinus Torvalds {
270f6d335c0SAl Viro 	struct key *key = file->private_data;
2719b3f26c9SDavid Howells 	struct afs_vnode *vnode;
2729b3f26c9SDavid Howells 	int ret = 0;
2731da177e4SLinus Torvalds 
274f6d335c0SAl Viro 	_enter("{%d},{%lu},,%d",
275f6d335c0SAl Viro 	       key_serial(key), mapping->host->i_ino, nr_pages);
276f6d335c0SAl Viro 
277f6d335c0SAl Viro 	ASSERT(key != NULL);
2781da177e4SLinus Torvalds 
2799b3f26c9SDavid Howells 	vnode = AFS_FS_I(mapping->host);
280ad2a8e60SDan Carpenter 	if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) {
2819b3f26c9SDavid Howells 		_leave(" = -ESTALE");
2829b3f26c9SDavid Howells 		return -ESTALE;
2831da177e4SLinus Torvalds 	}
2841da177e4SLinus Torvalds 
2859b3f26c9SDavid Howells 	/* attempt to read as many of the pages as possible */
2869b3f26c9SDavid Howells #ifdef CONFIG_AFS_FSCACHE
2879b3f26c9SDavid Howells 	ret = fscache_read_or_alloc_pages(vnode->cache,
2889b3f26c9SDavid Howells 					  mapping,
2899b3f26c9SDavid Howells 					  pages,
2909b3f26c9SDavid Howells 					  &nr_pages,
2919b3f26c9SDavid Howells 					  afs_file_readpage_read_complete,
2929b3f26c9SDavid Howells 					  NULL,
2939b3f26c9SDavid Howells 					  mapping_gfp_mask(mapping));
2949b3f26c9SDavid Howells #else
2959b3f26c9SDavid Howells 	ret = -ENOBUFS;
2969b3f26c9SDavid Howells #endif
2979b3f26c9SDavid Howells 
2989b3f26c9SDavid Howells 	switch (ret) {
2999b3f26c9SDavid Howells 		/* all pages are being read from the cache */
3009b3f26c9SDavid Howells 	case 0:
3019b3f26c9SDavid Howells 		BUG_ON(!list_empty(pages));
3029b3f26c9SDavid Howells 		BUG_ON(nr_pages != 0);
3039b3f26c9SDavid Howells 		_leave(" = 0 [reading all]");
3049b3f26c9SDavid Howells 		return 0;
3059b3f26c9SDavid Howells 
3069b3f26c9SDavid Howells 		/* there were pages that couldn't be read from the cache */
3079b3f26c9SDavid Howells 	case -ENODATA:
3089b3f26c9SDavid Howells 	case -ENOBUFS:
3099b3f26c9SDavid Howells 		break;
3109b3f26c9SDavid Howells 
3119b3f26c9SDavid Howells 		/* other error */
3129b3f26c9SDavid Howells 	default:
3131da177e4SLinus Torvalds 		_leave(" = %d", ret);
3149b3f26c9SDavid Howells 		return ret;
3159b3f26c9SDavid Howells 	}
3169b3f26c9SDavid Howells 
3179b3f26c9SDavid Howells 	/* load the missing pages from the network */
318f6d335c0SAl Viro 	ret = read_cache_pages(mapping, pages, afs_page_filler, key);
3199b3f26c9SDavid Howells 
3209b3f26c9SDavid Howells 	_leave(" = %d [netting]", ret);
3219b3f26c9SDavid Howells 	return ret;
322ec26815aSDavid Howells }
3231da177e4SLinus Torvalds 
3241da177e4SLinus Torvalds /*
32531143d5dSDavid Howells  * write back a dirty page
32631143d5dSDavid Howells  */
32731143d5dSDavid Howells static int afs_launder_page(struct page *page)
32831143d5dSDavid Howells {
32931143d5dSDavid Howells 	_enter("{%lu}", page->index);
33031143d5dSDavid Howells 
33131143d5dSDavid Howells 	return 0;
33231143d5dSDavid Howells }
33331143d5dSDavid Howells 
33431143d5dSDavid Howells /*
3359b3f26c9SDavid Howells  * invalidate part or all of a page
3369b3f26c9SDavid Howells  * - release a page and clean up its private data if offset is 0 (indicating
3379b3f26c9SDavid Howells  *   the entire page)
3389b3f26c9SDavid Howells  */
339d47992f8SLukas Czerner static void afs_invalidatepage(struct page *page, unsigned int offset,
340d47992f8SLukas Czerner 			       unsigned int length)
3419b3f26c9SDavid Howells {
3429b3f26c9SDavid Howells 	struct afs_writeback *wb = (struct afs_writeback *) page_private(page);
3439b3f26c9SDavid Howells 
344d47992f8SLukas Czerner 	_enter("{%lu},%u,%u", page->index, offset, length);
3459b3f26c9SDavid Howells 
3469b3f26c9SDavid Howells 	BUG_ON(!PageLocked(page));
3479b3f26c9SDavid Howells 
3489b3f26c9SDavid Howells 	/* we clean up only if the entire page is being invalidated */
34909cbfeafSKirill A. Shutemov 	if (offset == 0 && length == PAGE_SIZE) {
3509b3f26c9SDavid Howells #ifdef CONFIG_AFS_FSCACHE
3519b3f26c9SDavid Howells 		if (PageFsCache(page)) {
3529b3f26c9SDavid Howells 			struct afs_vnode *vnode = AFS_FS_I(page->mapping->host);
3539b3f26c9SDavid Howells 			fscache_wait_on_page_write(vnode->cache, page);
3549b3f26c9SDavid Howells 			fscache_uncache_page(vnode->cache, page);
3559b3f26c9SDavid Howells 		}
3569b3f26c9SDavid Howells #endif
3579b3f26c9SDavid Howells 
3589b3f26c9SDavid Howells 		if (PagePrivate(page)) {
3599b3f26c9SDavid Howells 			if (wb && !PageWriteback(page)) {
3609b3f26c9SDavid Howells 				set_page_private(page, 0);
3619b3f26c9SDavid Howells 				afs_put_writeback(wb);
3629b3f26c9SDavid Howells 			}
3639b3f26c9SDavid Howells 
3649b3f26c9SDavid Howells 			if (!page_private(page))
3659b3f26c9SDavid Howells 				ClearPagePrivate(page);
3669b3f26c9SDavid Howells 		}
3679b3f26c9SDavid Howells 	}
3689b3f26c9SDavid Howells 
3699b3f26c9SDavid Howells 	_leave("");
3709b3f26c9SDavid Howells }
3719b3f26c9SDavid Howells 
3729b3f26c9SDavid Howells /*
3739b3f26c9SDavid Howells  * release a page and clean up its private state if it's not busy
3749b3f26c9SDavid Howells  * - return true if the page can now be released, false if not
3751da177e4SLinus Torvalds  */
376416351f2SDavid Howells static int afs_releasepage(struct page *page, gfp_t gfp_flags)
3771da177e4SLinus Torvalds {
3789b3f26c9SDavid Howells 	struct afs_writeback *wb = (struct afs_writeback *) page_private(page);
379416351f2SDavid Howells 	struct afs_vnode *vnode = AFS_FS_I(page->mapping->host);
3801da177e4SLinus Torvalds 
381416351f2SDavid Howells 	_enter("{{%x:%u}[%lu],%lx},%x",
382416351f2SDavid Howells 	       vnode->fid.vid, vnode->fid.vnode, page->index, page->flags,
383416351f2SDavid Howells 	       gfp_flags);
3841da177e4SLinus Torvalds 
3859b3f26c9SDavid Howells 	/* deny if page is being written to the cache and the caller hasn't
3869b3f26c9SDavid Howells 	 * elected to wait */
3879b3f26c9SDavid Howells #ifdef CONFIG_AFS_FSCACHE
388201a1542SDavid Howells 	if (!fscache_maybe_release_page(vnode->cache, page, gfp_flags)) {
3899b3f26c9SDavid Howells 		_leave(" = F [cache busy]");
3909b3f26c9SDavid Howells 		return 0;
3919b3f26c9SDavid Howells 	}
3929b3f26c9SDavid Howells #endif
3939b3f26c9SDavid Howells 
3949b3f26c9SDavid Howells 	if (PagePrivate(page)) {
3959b3f26c9SDavid Howells 		if (wb) {
3969b3f26c9SDavid Howells 			set_page_private(page, 0);
3979b3f26c9SDavid Howells 			afs_put_writeback(wb);
3989b3f26c9SDavid Howells 		}
3999b3f26c9SDavid Howells 		ClearPagePrivate(page);
4009b3f26c9SDavid Howells 	}
4019b3f26c9SDavid Howells 
4029b3f26c9SDavid Howells 	/* indicate that the page can be released */
4039b3f26c9SDavid Howells 	_leave(" = T");
4049b3f26c9SDavid Howells 	return 1;
405ec26815aSDavid Howells }
406