xref: /openbmc/linux/fs/ceph/cache.c (revision 1d8f8360)
199ccbd22SMilosz Tanski /*
299ccbd22SMilosz Tanski  * Ceph cache definitions.
399ccbd22SMilosz Tanski  *
499ccbd22SMilosz Tanski  *  Copyright (C) 2013 by Adfin Solutions, Inc. All Rights Reserved.
599ccbd22SMilosz Tanski  *  Written by Milosz Tanski (milosz@adfin.com)
699ccbd22SMilosz Tanski  *
799ccbd22SMilosz Tanski  *  This program is free software; you can redistribute it and/or modify
899ccbd22SMilosz Tanski  *  it under the terms of the GNU General Public License version 2
999ccbd22SMilosz Tanski  *  as published by the Free Software Foundation.
1099ccbd22SMilosz Tanski  *
1199ccbd22SMilosz Tanski  *  This program is distributed in the hope that it will be useful,
1299ccbd22SMilosz Tanski  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
1399ccbd22SMilosz Tanski  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1499ccbd22SMilosz Tanski  *  GNU General Public License for more details.
1599ccbd22SMilosz Tanski  *
1699ccbd22SMilosz Tanski  *  You should have received a copy of the GNU General Public License
1799ccbd22SMilosz Tanski  *  along with this program; if not, write to:
1899ccbd22SMilosz Tanski  *  Free Software Foundation
1999ccbd22SMilosz Tanski  *  51 Franklin Street, Fifth Floor
2099ccbd22SMilosz Tanski  *  Boston, MA  02111-1301  USA
2199ccbd22SMilosz Tanski  *
2299ccbd22SMilosz Tanski  */
2399ccbd22SMilosz Tanski 
2499ccbd22SMilosz Tanski #include "super.h"
2599ccbd22SMilosz Tanski #include "cache.h"
2699ccbd22SMilosz Tanski 
2799ccbd22SMilosz Tanski struct ceph_aux_inode {
28f6973c09SYan, Zheng 	u64 		version;
2999ccbd22SMilosz Tanski 	struct timespec	mtime;
3099ccbd22SMilosz Tanski 	loff_t          size;
3199ccbd22SMilosz Tanski };
3299ccbd22SMilosz Tanski 
3399ccbd22SMilosz Tanski struct fscache_netfs ceph_cache_netfs = {
3499ccbd22SMilosz Tanski 	.name		= "ceph",
3599ccbd22SMilosz Tanski 	.version	= 0,
3699ccbd22SMilosz Tanski };
3799ccbd22SMilosz Tanski 
381d8f8360SYan, Zheng static DEFINE_MUTEX(ceph_fscache_lock);
391d8f8360SYan, Zheng static LIST_HEAD(ceph_fscache_list);
401d8f8360SYan, Zheng 
411d8f8360SYan, Zheng struct ceph_fscache_entry {
421d8f8360SYan, Zheng 	struct list_head list;
431d8f8360SYan, Zheng 	struct fscache_cookie *fscache;
441d8f8360SYan, Zheng 	struct ceph_fsid fsid;
451d8f8360SYan, Zheng 	size_t uniq_len;
461d8f8360SYan, Zheng 	char uniquifier[0];
471d8f8360SYan, Zheng };
481d8f8360SYan, Zheng 
4999ccbd22SMilosz Tanski static uint16_t ceph_fscache_session_get_key(const void *cookie_netfs_data,
5099ccbd22SMilosz Tanski 					     void *buffer, uint16_t maxbuf)
5199ccbd22SMilosz Tanski {
5299ccbd22SMilosz Tanski 	const struct ceph_fs_client* fsc = cookie_netfs_data;
531d8f8360SYan, Zheng 	const char *fscache_uniq = fsc->mount_options->fscache_uniq;
541d8f8360SYan, Zheng 	uint16_t fsid_len, uniq_len;
5599ccbd22SMilosz Tanski 
561d8f8360SYan, Zheng 	fsid_len = sizeof(fsc->client->fsid);
571d8f8360SYan, Zheng 	uniq_len = fscache_uniq ? strlen(fscache_uniq) : 0;
581d8f8360SYan, Zheng 	if (fsid_len + uniq_len > maxbuf)
5999ccbd22SMilosz Tanski 		return 0;
6099ccbd22SMilosz Tanski 
611d8f8360SYan, Zheng 	memcpy(buffer, &fsc->client->fsid, fsid_len);
621d8f8360SYan, Zheng 	if (uniq_len)
631d8f8360SYan, Zheng 		memcpy(buffer + fsid_len, fscache_uniq, uniq_len);
641d8f8360SYan, Zheng 
651d8f8360SYan, Zheng 	return fsid_len + uniq_len;
6699ccbd22SMilosz Tanski }
6799ccbd22SMilosz Tanski 
6899ccbd22SMilosz Tanski static const struct fscache_cookie_def ceph_fscache_fsid_object_def = {
6999ccbd22SMilosz Tanski 	.name		= "CEPH.fsid",
7099ccbd22SMilosz Tanski 	.type		= FSCACHE_COOKIE_TYPE_INDEX,
7199ccbd22SMilosz Tanski 	.get_key	= ceph_fscache_session_get_key,
7299ccbd22SMilosz Tanski };
7399ccbd22SMilosz Tanski 
74971f0bdeSMilosz Tanski int ceph_fscache_register(void)
7599ccbd22SMilosz Tanski {
7699ccbd22SMilosz Tanski 	return fscache_register_netfs(&ceph_cache_netfs);
7799ccbd22SMilosz Tanski }
7899ccbd22SMilosz Tanski 
79971f0bdeSMilosz Tanski void ceph_fscache_unregister(void)
8099ccbd22SMilosz Tanski {
8199ccbd22SMilosz Tanski 	fscache_unregister_netfs(&ceph_cache_netfs);
8299ccbd22SMilosz Tanski }
8399ccbd22SMilosz Tanski 
8499ccbd22SMilosz Tanski int ceph_fscache_register_fs(struct ceph_fs_client* fsc)
8599ccbd22SMilosz Tanski {
861d8f8360SYan, Zheng 	const struct ceph_fsid *fsid = &fsc->client->fsid;
871d8f8360SYan, Zheng 	const char *fscache_uniq = fsc->mount_options->fscache_uniq;
881d8f8360SYan, Zheng 	size_t uniq_len = fscache_uniq ? strlen(fscache_uniq) : 0;
891d8f8360SYan, Zheng 	struct ceph_fscache_entry *ent;
901d8f8360SYan, Zheng 	int err = 0;
911d8f8360SYan, Zheng 
921d8f8360SYan, Zheng 	mutex_lock(&ceph_fscache_lock);
931d8f8360SYan, Zheng 	list_for_each_entry(ent, &ceph_fscache_list, list) {
941d8f8360SYan, Zheng 		if (memcmp(&ent->fsid, fsid, sizeof(*fsid)))
951d8f8360SYan, Zheng 			continue;
961d8f8360SYan, Zheng 		if (ent->uniq_len != uniq_len)
971d8f8360SYan, Zheng 			continue;
981d8f8360SYan, Zheng 		if (uniq_len && memcmp(ent->uniquifier, fscache_uniq, uniq_len))
991d8f8360SYan, Zheng 			continue;
1001d8f8360SYan, Zheng 
1011d8f8360SYan, Zheng 		pr_err("fscache cookie already registered for fsid %pU\n", fsid);
1021d8f8360SYan, Zheng 		pr_err("  use fsc=%%s mount option to specify a uniquifier\n");
1031d8f8360SYan, Zheng 		err = -EBUSY;
1041d8f8360SYan, Zheng 		goto out_unlock;
1051d8f8360SYan, Zheng 	}
1061d8f8360SYan, Zheng 
1071d8f8360SYan, Zheng 	ent = kzalloc(sizeof(*ent) + uniq_len, GFP_KERNEL);
1081d8f8360SYan, Zheng 	if (!ent) {
1091d8f8360SYan, Zheng 		err = -ENOMEM;
1101d8f8360SYan, Zheng 		goto out_unlock;
1111d8f8360SYan, Zheng 	}
1121d8f8360SYan, Zheng 
11399ccbd22SMilosz Tanski 	fsc->fscache = fscache_acquire_cookie(ceph_cache_netfs.primary_index,
11499ccbd22SMilosz Tanski 					      &ceph_fscache_fsid_object_def,
11594d30ae9SDavid Howells 					      fsc, true);
11699ccbd22SMilosz Tanski 
1171d8f8360SYan, Zheng 	if (fsc->fscache) {
1181d8f8360SYan, Zheng 		memcpy(&ent->fsid, fsid, sizeof(*fsid));
1191d8f8360SYan, Zheng 		if (uniq_len > 0) {
1201d8f8360SYan, Zheng 			memcpy(&ent->uniquifier, fscache_uniq, uniq_len);
1211d8f8360SYan, Zheng 			ent->uniq_len = uniq_len;
1221d8f8360SYan, Zheng 		}
1231d8f8360SYan, Zheng 		ent->fscache = fsc->fscache;
1241d8f8360SYan, Zheng 		list_add_tail(&ent->list, &ceph_fscache_list);
1251d8f8360SYan, Zheng 	} else {
1261d8f8360SYan, Zheng 		kfree(ent);
1271d8f8360SYan, Zheng 		pr_err("unable to register fscache cookie for fsid %pU\n",
1281d8f8360SYan, Zheng 		       fsid);
1291d8f8360SYan, Zheng 		/* all other fs ignore this error */
1301d8f8360SYan, Zheng 	}
1311d8f8360SYan, Zheng out_unlock:
1321d8f8360SYan, Zheng 	mutex_unlock(&ceph_fscache_lock);
1331d8f8360SYan, Zheng 	return err;
13499ccbd22SMilosz Tanski }
13599ccbd22SMilosz Tanski 
13699ccbd22SMilosz Tanski static uint16_t ceph_fscache_inode_get_key(const void *cookie_netfs_data,
13799ccbd22SMilosz Tanski 					   void *buffer, uint16_t maxbuf)
13899ccbd22SMilosz Tanski {
13999ccbd22SMilosz Tanski 	const struct ceph_inode_info* ci = cookie_netfs_data;
14099ccbd22SMilosz Tanski 	uint16_t klen;
14199ccbd22SMilosz Tanski 
1421291fb95SGeliang Tang 	/* use ceph virtual inode (id + snapshot) */
14399ccbd22SMilosz Tanski 	klen = sizeof(ci->i_vino);
14499ccbd22SMilosz Tanski 	if (klen > maxbuf)
14599ccbd22SMilosz Tanski 		return 0;
14699ccbd22SMilosz Tanski 
14799ccbd22SMilosz Tanski 	memcpy(buffer, &ci->i_vino, klen);
14899ccbd22SMilosz Tanski 	return klen;
14999ccbd22SMilosz Tanski }
15099ccbd22SMilosz Tanski 
15199ccbd22SMilosz Tanski static uint16_t ceph_fscache_inode_get_aux(const void *cookie_netfs_data,
15299ccbd22SMilosz Tanski 					   void *buffer, uint16_t bufmax)
15399ccbd22SMilosz Tanski {
15499ccbd22SMilosz Tanski 	struct ceph_aux_inode aux;
15599ccbd22SMilosz Tanski 	const struct ceph_inode_info* ci = cookie_netfs_data;
15699ccbd22SMilosz Tanski 	const struct inode* inode = &ci->vfs_inode;
15799ccbd22SMilosz Tanski 
15899ccbd22SMilosz Tanski 	memset(&aux, 0, sizeof(aux));
159f6973c09SYan, Zheng 	aux.version = ci->i_version;
16099ccbd22SMilosz Tanski 	aux.mtime = inode->i_mtime;
16199c88e69SYan, Zheng 	aux.size = i_size_read(inode);
16299ccbd22SMilosz Tanski 
16399ccbd22SMilosz Tanski 	memcpy(buffer, &aux, sizeof(aux));
16499ccbd22SMilosz Tanski 
16599ccbd22SMilosz Tanski 	return sizeof(aux);
16699ccbd22SMilosz Tanski }
16799ccbd22SMilosz Tanski 
16899ccbd22SMilosz Tanski static void ceph_fscache_inode_get_attr(const void *cookie_netfs_data,
16999ccbd22SMilosz Tanski 					uint64_t *size)
17099ccbd22SMilosz Tanski {
17199ccbd22SMilosz Tanski 	const struct ceph_inode_info* ci = cookie_netfs_data;
17299c88e69SYan, Zheng 	*size = i_size_read(&ci->vfs_inode);
17399ccbd22SMilosz Tanski }
17499ccbd22SMilosz Tanski 
17599ccbd22SMilosz Tanski static enum fscache_checkaux ceph_fscache_inode_check_aux(
17699ccbd22SMilosz Tanski 	void *cookie_netfs_data, const void *data, uint16_t dlen)
17799ccbd22SMilosz Tanski {
17899ccbd22SMilosz Tanski 	struct ceph_aux_inode aux;
17999ccbd22SMilosz Tanski 	struct ceph_inode_info* ci = cookie_netfs_data;
18099ccbd22SMilosz Tanski 	struct inode* inode = &ci->vfs_inode;
18199ccbd22SMilosz Tanski 
18299ccbd22SMilosz Tanski 	if (dlen != sizeof(aux))
18399ccbd22SMilosz Tanski 		return FSCACHE_CHECKAUX_OBSOLETE;
18499ccbd22SMilosz Tanski 
18599ccbd22SMilosz Tanski 	memset(&aux, 0, sizeof(aux));
186f6973c09SYan, Zheng 	aux.version = ci->i_version;
18799ccbd22SMilosz Tanski 	aux.mtime = inode->i_mtime;
18899c88e69SYan, Zheng 	aux.size = i_size_read(inode);
18999ccbd22SMilosz Tanski 
19099ccbd22SMilosz Tanski 	if (memcmp(data, &aux, sizeof(aux)) != 0)
19199ccbd22SMilosz Tanski 		return FSCACHE_CHECKAUX_OBSOLETE;
19299ccbd22SMilosz Tanski 
19399ccbd22SMilosz Tanski 	dout("ceph inode 0x%p cached okay", ci);
19499ccbd22SMilosz Tanski 	return FSCACHE_CHECKAUX_OKAY;
19599ccbd22SMilosz Tanski }
19699ccbd22SMilosz Tanski 
19799ccbd22SMilosz Tanski static void ceph_fscache_inode_now_uncached(void* cookie_netfs_data)
19899ccbd22SMilosz Tanski {
19999ccbd22SMilosz Tanski 	struct ceph_inode_info* ci = cookie_netfs_data;
20099ccbd22SMilosz Tanski 	struct pagevec pvec;
20199ccbd22SMilosz Tanski 	pgoff_t first;
20299ccbd22SMilosz Tanski 	int loop, nr_pages;
20399ccbd22SMilosz Tanski 
20499ccbd22SMilosz Tanski 	pagevec_init(&pvec, 0);
20599ccbd22SMilosz Tanski 	first = 0;
20699ccbd22SMilosz Tanski 
20799ccbd22SMilosz Tanski 	dout("ceph inode 0x%p now uncached", ci);
20899ccbd22SMilosz Tanski 
20999ccbd22SMilosz Tanski 	while (1) {
21099ccbd22SMilosz Tanski 		nr_pages = pagevec_lookup(&pvec, ci->vfs_inode.i_mapping, first,
21199ccbd22SMilosz Tanski 					  PAGEVEC_SIZE - pagevec_count(&pvec));
21299ccbd22SMilosz Tanski 
21399ccbd22SMilosz Tanski 		if (!nr_pages)
21499ccbd22SMilosz Tanski 			break;
21599ccbd22SMilosz Tanski 
21699ccbd22SMilosz Tanski 		for (loop = 0; loop < nr_pages; loop++)
21799ccbd22SMilosz Tanski 			ClearPageFsCache(pvec.pages[loop]);
21899ccbd22SMilosz Tanski 
21999ccbd22SMilosz Tanski 		first = pvec.pages[nr_pages - 1]->index + 1;
22099ccbd22SMilosz Tanski 
22199ccbd22SMilosz Tanski 		pvec.nr = nr_pages;
22299ccbd22SMilosz Tanski 		pagevec_release(&pvec);
22399ccbd22SMilosz Tanski 		cond_resched();
22499ccbd22SMilosz Tanski 	}
22599ccbd22SMilosz Tanski }
22699ccbd22SMilosz Tanski 
22799ccbd22SMilosz Tanski static const struct fscache_cookie_def ceph_fscache_inode_object_def = {
22899ccbd22SMilosz Tanski 	.name		= "CEPH.inode",
22999ccbd22SMilosz Tanski 	.type		= FSCACHE_COOKIE_TYPE_DATAFILE,
23099ccbd22SMilosz Tanski 	.get_key	= ceph_fscache_inode_get_key,
23199ccbd22SMilosz Tanski 	.get_attr	= ceph_fscache_inode_get_attr,
23299ccbd22SMilosz Tanski 	.get_aux	= ceph_fscache_inode_get_aux,
23399ccbd22SMilosz Tanski 	.check_aux	= ceph_fscache_inode_check_aux,
23499ccbd22SMilosz Tanski 	.now_uncached	= ceph_fscache_inode_now_uncached,
23599ccbd22SMilosz Tanski };
23699ccbd22SMilosz Tanski 
23746b59b2bSYan, Zheng void ceph_fscache_register_inode_cookie(struct inode *inode)
23899ccbd22SMilosz Tanski {
23946b59b2bSYan, Zheng 	struct ceph_inode_info *ci = ceph_inode(inode);
24046b59b2bSYan, Zheng 	struct ceph_fs_client *fsc = ceph_inode_to_client(inode);
24199ccbd22SMilosz Tanski 
24299ccbd22SMilosz Tanski 	/* No caching for filesystem */
24399ccbd22SMilosz Tanski 	if (fsc->fscache == NULL)
24499ccbd22SMilosz Tanski 		return;
24599ccbd22SMilosz Tanski 
24699ccbd22SMilosz Tanski 	/* Only cache for regular files that are read only */
24746b59b2bSYan, Zheng 	if (!S_ISREG(inode->i_mode))
24899ccbd22SMilosz Tanski 		return;
24999ccbd22SMilosz Tanski 
25046b59b2bSYan, Zheng 	inode_lock_nested(inode, I_MUTEX_CHILD);
25146b59b2bSYan, Zheng 	if (!ci->fscache) {
25299ccbd22SMilosz Tanski 		ci->fscache = fscache_acquire_cookie(fsc->fscache,
25399ccbd22SMilosz Tanski 					&ceph_fscache_inode_object_def,
25446b59b2bSYan, Zheng 					ci, false);
25546b59b2bSYan, Zheng 	}
2565955102cSAl Viro 	inode_unlock(inode);
25799ccbd22SMilosz Tanski }
25899ccbd22SMilosz Tanski 
25999ccbd22SMilosz Tanski void ceph_fscache_unregister_inode_cookie(struct ceph_inode_info* ci)
26099ccbd22SMilosz Tanski {
26199ccbd22SMilosz Tanski 	struct fscache_cookie* cookie;
26299ccbd22SMilosz Tanski 
26399ccbd22SMilosz Tanski 	if ((cookie = ci->fscache) == NULL)
26499ccbd22SMilosz Tanski 		return;
26599ccbd22SMilosz Tanski 
26699ccbd22SMilosz Tanski 	ci->fscache = NULL;
26799ccbd22SMilosz Tanski 
26899ccbd22SMilosz Tanski 	fscache_uncache_all_inode_pages(cookie, &ci->vfs_inode);
26999ccbd22SMilosz Tanski 	fscache_relinquish_cookie(cookie, 0);
27099ccbd22SMilosz Tanski }
27199ccbd22SMilosz Tanski 
27246b59b2bSYan, Zheng static bool ceph_fscache_can_enable(void *data)
27346b59b2bSYan, Zheng {
27446b59b2bSYan, Zheng 	struct inode *inode = data;
27546b59b2bSYan, Zheng 	return !inode_is_open_for_write(inode);
27646b59b2bSYan, Zheng }
27746b59b2bSYan, Zheng 
27846b59b2bSYan, Zheng void ceph_fscache_file_set_cookie(struct inode *inode, struct file *filp)
27946b59b2bSYan, Zheng {
28046b59b2bSYan, Zheng 	struct ceph_inode_info *ci = ceph_inode(inode);
28146b59b2bSYan, Zheng 
28246b59b2bSYan, Zheng 	if (!fscache_cookie_valid(ci->fscache))
28346b59b2bSYan, Zheng 		return;
28446b59b2bSYan, Zheng 
28546b59b2bSYan, Zheng 	if (inode_is_open_for_write(inode)) {
28646b59b2bSYan, Zheng 		dout("fscache_file_set_cookie %p %p disabling cache\n",
28746b59b2bSYan, Zheng 		     inode, filp);
28846b59b2bSYan, Zheng 		fscache_disable_cookie(ci->fscache, false);
28946b59b2bSYan, Zheng 		fscache_uncache_all_inode_pages(ci->fscache, inode);
29046b59b2bSYan, Zheng 	} else {
29146b59b2bSYan, Zheng 		fscache_enable_cookie(ci->fscache, ceph_fscache_can_enable,
29246b59b2bSYan, Zheng 				inode);
29346b59b2bSYan, Zheng 		if (fscache_cookie_enabled(ci->fscache)) {
2940fbc5360SColin Ian King 			dout("fscache_file_set_cookie %p %p enabling cache\n",
29546b59b2bSYan, Zheng 			     inode, filp);
29646b59b2bSYan, Zheng 		}
29746b59b2bSYan, Zheng 	}
29846b59b2bSYan, Zheng }
29946b59b2bSYan, Zheng 
30099ccbd22SMilosz Tanski static void ceph_vfs_readpage_complete(struct page *page, void *data, int error)
30199ccbd22SMilosz Tanski {
30299ccbd22SMilosz Tanski 	if (!error)
30399ccbd22SMilosz Tanski 		SetPageUptodate(page);
30499ccbd22SMilosz Tanski }
30599ccbd22SMilosz Tanski 
30699ccbd22SMilosz Tanski static void ceph_vfs_readpage_complete_unlock(struct page *page, void *data, int error)
30799ccbd22SMilosz Tanski {
30899ccbd22SMilosz Tanski 	if (!error)
30999ccbd22SMilosz Tanski 		SetPageUptodate(page);
31099ccbd22SMilosz Tanski 
31199ccbd22SMilosz Tanski 	unlock_page(page);
31299ccbd22SMilosz Tanski }
31399ccbd22SMilosz Tanski 
3143b33f692SZhang Zhuoyu static inline bool cache_valid(struct ceph_inode_info *ci)
31599ccbd22SMilosz Tanski {
316f7f7e7a0SYan, Zheng 	return ci->i_fscache_gen == ci->i_rdcache_gen;
31799ccbd22SMilosz Tanski }
31899ccbd22SMilosz Tanski 
31999ccbd22SMilosz Tanski 
32099ccbd22SMilosz Tanski /* Atempt to read from the fscache,
32199ccbd22SMilosz Tanski  *
32299ccbd22SMilosz Tanski  * This function is called from the readpage_nounlock context. DO NOT attempt to
32399ccbd22SMilosz Tanski  * unlock the page here (or in the callback).
32499ccbd22SMilosz Tanski  */
32599ccbd22SMilosz Tanski int ceph_readpage_from_fscache(struct inode *inode, struct page *page)
32699ccbd22SMilosz Tanski {
32799ccbd22SMilosz Tanski 	struct ceph_inode_info *ci = ceph_inode(inode);
32899ccbd22SMilosz Tanski 	int ret;
32999ccbd22SMilosz Tanski 
33099ccbd22SMilosz Tanski 	if (!cache_valid(ci))
33199ccbd22SMilosz Tanski 		return -ENOBUFS;
33299ccbd22SMilosz Tanski 
33399ccbd22SMilosz Tanski 	ret = fscache_read_or_alloc_page(ci->fscache, page,
33499ccbd22SMilosz Tanski 					 ceph_vfs_readpage_complete, NULL,
33599ccbd22SMilosz Tanski 					 GFP_KERNEL);
33699ccbd22SMilosz Tanski 
33799ccbd22SMilosz Tanski 	switch (ret) {
33899ccbd22SMilosz Tanski 		case 0: /* Page found */
33999ccbd22SMilosz Tanski 			dout("page read submitted\n");
34099ccbd22SMilosz Tanski 			return 0;
34199ccbd22SMilosz Tanski 		case -ENOBUFS: /* Pages were not found, and can't be */
34299ccbd22SMilosz Tanski 		case -ENODATA: /* Pages were not found */
34399ccbd22SMilosz Tanski 			dout("page/inode not in cache\n");
34499ccbd22SMilosz Tanski 			return ret;
34599ccbd22SMilosz Tanski 		default:
34699ccbd22SMilosz Tanski 			dout("%s: unknown error ret = %i\n", __func__, ret);
34799ccbd22SMilosz Tanski 			return ret;
34899ccbd22SMilosz Tanski 	}
34999ccbd22SMilosz Tanski }
35099ccbd22SMilosz Tanski 
35199ccbd22SMilosz Tanski int ceph_readpages_from_fscache(struct inode *inode,
35299ccbd22SMilosz Tanski 				  struct address_space *mapping,
35399ccbd22SMilosz Tanski 				  struct list_head *pages,
35499ccbd22SMilosz Tanski 				  unsigned *nr_pages)
35599ccbd22SMilosz Tanski {
35699ccbd22SMilosz Tanski 	struct ceph_inode_info *ci = ceph_inode(inode);
35799ccbd22SMilosz Tanski 	int ret;
35899ccbd22SMilosz Tanski 
35999ccbd22SMilosz Tanski 	if (!cache_valid(ci))
36099ccbd22SMilosz Tanski 		return -ENOBUFS;
36199ccbd22SMilosz Tanski 
36299ccbd22SMilosz Tanski 	ret = fscache_read_or_alloc_pages(ci->fscache, mapping, pages, nr_pages,
36399ccbd22SMilosz Tanski 					  ceph_vfs_readpage_complete_unlock,
36499ccbd22SMilosz Tanski 					  NULL, mapping_gfp_mask(mapping));
36599ccbd22SMilosz Tanski 
36699ccbd22SMilosz Tanski 	switch (ret) {
36799ccbd22SMilosz Tanski 		case 0: /* All pages found */
36899ccbd22SMilosz Tanski 			dout("all-page read submitted\n");
36999ccbd22SMilosz Tanski 			return 0;
37099ccbd22SMilosz Tanski 		case -ENOBUFS: /* Some pages were not found, and can't be */
37199ccbd22SMilosz Tanski 		case -ENODATA: /* some pages were not found */
37299ccbd22SMilosz Tanski 			dout("page/inode not in cache\n");
37399ccbd22SMilosz Tanski 			return ret;
37499ccbd22SMilosz Tanski 		default:
37599ccbd22SMilosz Tanski 			dout("%s: unknown error ret = %i\n", __func__, ret);
37699ccbd22SMilosz Tanski 			return ret;
37799ccbd22SMilosz Tanski 	}
37899ccbd22SMilosz Tanski }
37999ccbd22SMilosz Tanski 
38099ccbd22SMilosz Tanski void ceph_readpage_to_fscache(struct inode *inode, struct page *page)
38199ccbd22SMilosz Tanski {
38299ccbd22SMilosz Tanski 	struct ceph_inode_info *ci = ceph_inode(inode);
38399ccbd22SMilosz Tanski 	int ret;
38499ccbd22SMilosz Tanski 
3859b8dd1e8SMilosz Tanski 	if (!PageFsCache(page))
3869b8dd1e8SMilosz Tanski 		return;
3879b8dd1e8SMilosz Tanski 
38899ccbd22SMilosz Tanski 	if (!cache_valid(ci))
38999ccbd22SMilosz Tanski 		return;
39099ccbd22SMilosz Tanski 
39199ccbd22SMilosz Tanski 	ret = fscache_write_page(ci->fscache, page, GFP_KERNEL);
39299ccbd22SMilosz Tanski 	if (ret)
39399ccbd22SMilosz Tanski 		 fscache_uncache_page(ci->fscache, page);
39499ccbd22SMilosz Tanski }
39599ccbd22SMilosz Tanski 
39699ccbd22SMilosz Tanski void ceph_invalidate_fscache_page(struct inode* inode, struct page *page)
39799ccbd22SMilosz Tanski {
39899ccbd22SMilosz Tanski 	struct ceph_inode_info *ci = ceph_inode(inode);
39999ccbd22SMilosz Tanski 
400ffc79664SMilosz Tanski 	if (!PageFsCache(page))
401ffc79664SMilosz Tanski 		return;
402ffc79664SMilosz Tanski 
40399ccbd22SMilosz Tanski 	fscache_wait_on_page_write(ci->fscache, page);
40499ccbd22SMilosz Tanski 	fscache_uncache_page(ci->fscache, page);
40599ccbd22SMilosz Tanski }
40699ccbd22SMilosz Tanski 
40799ccbd22SMilosz Tanski void ceph_fscache_unregister_fs(struct ceph_fs_client* fsc)
40899ccbd22SMilosz Tanski {
4091d8f8360SYan, Zheng 	if (fscache_cookie_valid(fsc->fscache)) {
4101d8f8360SYan, Zheng 		struct ceph_fscache_entry *ent;
4111d8f8360SYan, Zheng 		bool found = false;
4121d8f8360SYan, Zheng 
4131d8f8360SYan, Zheng 		mutex_lock(&ceph_fscache_lock);
4141d8f8360SYan, Zheng 		list_for_each_entry(ent, &ceph_fscache_list, list) {
4151d8f8360SYan, Zheng 			if (ent->fscache == fsc->fscache) {
4161d8f8360SYan, Zheng 				list_del(&ent->list);
4171d8f8360SYan, Zheng 				kfree(ent);
4181d8f8360SYan, Zheng 				found = true;
4191d8f8360SYan, Zheng 				break;
4201d8f8360SYan, Zheng 			}
4211d8f8360SYan, Zheng 		}
4221d8f8360SYan, Zheng 		WARN_ON_ONCE(!found);
4231d8f8360SYan, Zheng 		mutex_unlock(&ceph_fscache_lock);
4241d8f8360SYan, Zheng 
4251d8f8360SYan, Zheng 		__fscache_relinquish_cookie(fsc->fscache, 0);
4261d8f8360SYan, Zheng 	}
42799ccbd22SMilosz Tanski 	fsc->fscache = NULL;
42899ccbd22SMilosz Tanski }
42999ccbd22SMilosz Tanski 
430f7f7e7a0SYan, Zheng /*
431f7f7e7a0SYan, Zheng  * caller should hold CEPH_CAP_FILE_{RD,CACHE}
432f7f7e7a0SYan, Zheng  */
433f7f7e7a0SYan, Zheng void ceph_fscache_revalidate_cookie(struct ceph_inode_info *ci)
43499ccbd22SMilosz Tanski {
435f7f7e7a0SYan, Zheng 	if (cache_valid(ci))
436e81568ebSMilosz Tanski 		return;
437e81568ebSMilosz Tanski 
438f7f7e7a0SYan, Zheng 	/* resue i_truncate_mutex. There should be no pending
439f7f7e7a0SYan, Zheng 	 * truncate while the caller holds CEPH_CAP_FILE_RD */
440f7f7e7a0SYan, Zheng 	mutex_lock(&ci->i_truncate_mutex);
441f7f7e7a0SYan, Zheng 	if (!cache_valid(ci)) {
442f7f7e7a0SYan, Zheng 		if (fscache_check_consistency(ci->fscache))
443f7f7e7a0SYan, Zheng 			fscache_invalidate(ci->fscache);
444f7f7e7a0SYan, Zheng 		spin_lock(&ci->i_ceph_lock);
445f7f7e7a0SYan, Zheng 		ci->i_fscache_gen = ci->i_rdcache_gen;
446f7f7e7a0SYan, Zheng 		spin_unlock(&ci->i_ceph_lock);
44799ccbd22SMilosz Tanski 	}
448f7f7e7a0SYan, Zheng 	mutex_unlock(&ci->i_truncate_mutex);
44999ccbd22SMilosz Tanski }
450