xref: /openbmc/linux/fs/ceph/cache.c (revision 1f327613)
11f327613SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
299ccbd22SMilosz Tanski /*
399ccbd22SMilosz Tanski  * Ceph cache definitions.
499ccbd22SMilosz Tanski  *
599ccbd22SMilosz Tanski  *  Copyright (C) 2013 by Adfin Solutions, Inc. All Rights Reserved.
699ccbd22SMilosz Tanski  *  Written by Milosz Tanski (milosz@adfin.com)
799ccbd22SMilosz Tanski  */
899ccbd22SMilosz Tanski 
999ccbd22SMilosz Tanski #include "super.h"
1099ccbd22SMilosz Tanski #include "cache.h"
1199ccbd22SMilosz Tanski 
1299ccbd22SMilosz Tanski struct ceph_aux_inode {
13f6973c09SYan, Zheng 	u64 	version;
149bbeab41SArnd Bergmann 	u64	mtime_sec;
159bbeab41SArnd Bergmann 	u64	mtime_nsec;
1699ccbd22SMilosz Tanski };
1799ccbd22SMilosz Tanski 
1899ccbd22SMilosz Tanski struct fscache_netfs ceph_cache_netfs = {
1999ccbd22SMilosz Tanski 	.name		= "ceph",
2099ccbd22SMilosz Tanski 	.version	= 0,
2199ccbd22SMilosz Tanski };
2299ccbd22SMilosz Tanski 
231d8f8360SYan, Zheng static DEFINE_MUTEX(ceph_fscache_lock);
241d8f8360SYan, Zheng static LIST_HEAD(ceph_fscache_list);
251d8f8360SYan, Zheng 
261d8f8360SYan, Zheng struct ceph_fscache_entry {
271d8f8360SYan, Zheng 	struct list_head list;
281d8f8360SYan, Zheng 	struct fscache_cookie *fscache;
291d8f8360SYan, Zheng 	size_t uniq_len;
30402cb8ddSDavid Howells 	/* The following members must be last */
31402cb8ddSDavid Howells 	struct ceph_fsid fsid;
321d8f8360SYan, Zheng 	char uniquifier[0];
331d8f8360SYan, Zheng };
341d8f8360SYan, Zheng 
3599ccbd22SMilosz Tanski static const struct fscache_cookie_def ceph_fscache_fsid_object_def = {
3699ccbd22SMilosz Tanski 	.name		= "CEPH.fsid",
3799ccbd22SMilosz Tanski 	.type		= FSCACHE_COOKIE_TYPE_INDEX,
3899ccbd22SMilosz Tanski };
3999ccbd22SMilosz Tanski 
4057a35dfbSChengguang Xu int __init ceph_fscache_register(void)
4199ccbd22SMilosz Tanski {
4299ccbd22SMilosz Tanski 	return fscache_register_netfs(&ceph_cache_netfs);
4399ccbd22SMilosz Tanski }
4499ccbd22SMilosz Tanski 
45971f0bdeSMilosz Tanski void ceph_fscache_unregister(void)
4699ccbd22SMilosz Tanski {
4799ccbd22SMilosz Tanski 	fscache_unregister_netfs(&ceph_cache_netfs);
4899ccbd22SMilosz Tanski }
4999ccbd22SMilosz Tanski 
5099ccbd22SMilosz Tanski int ceph_fscache_register_fs(struct ceph_fs_client* fsc)
5199ccbd22SMilosz Tanski {
521d8f8360SYan, Zheng 	const struct ceph_fsid *fsid = &fsc->client->fsid;
531d8f8360SYan, Zheng 	const char *fscache_uniq = fsc->mount_options->fscache_uniq;
541d8f8360SYan, Zheng 	size_t uniq_len = fscache_uniq ? strlen(fscache_uniq) : 0;
551d8f8360SYan, Zheng 	struct ceph_fscache_entry *ent;
561d8f8360SYan, Zheng 	int err = 0;
571d8f8360SYan, Zheng 
581d8f8360SYan, Zheng 	mutex_lock(&ceph_fscache_lock);
591d8f8360SYan, Zheng 	list_for_each_entry(ent, &ceph_fscache_list, list) {
601d8f8360SYan, Zheng 		if (memcmp(&ent->fsid, fsid, sizeof(*fsid)))
611d8f8360SYan, Zheng 			continue;
621d8f8360SYan, Zheng 		if (ent->uniq_len != uniq_len)
631d8f8360SYan, Zheng 			continue;
641d8f8360SYan, Zheng 		if (uniq_len && memcmp(ent->uniquifier, fscache_uniq, uniq_len))
651d8f8360SYan, Zheng 			continue;
661d8f8360SYan, Zheng 
671d8f8360SYan, Zheng 		pr_err("fscache cookie already registered for fsid %pU\n", fsid);
681d8f8360SYan, Zheng 		pr_err("  use fsc=%%s mount option to specify a uniquifier\n");
691d8f8360SYan, Zheng 		err = -EBUSY;
701d8f8360SYan, Zheng 		goto out_unlock;
711d8f8360SYan, Zheng 	}
721d8f8360SYan, Zheng 
731d8f8360SYan, Zheng 	ent = kzalloc(sizeof(*ent) + uniq_len, GFP_KERNEL);
741d8f8360SYan, Zheng 	if (!ent) {
751d8f8360SYan, Zheng 		err = -ENOMEM;
761d8f8360SYan, Zheng 		goto out_unlock;
771d8f8360SYan, Zheng 	}
781d8f8360SYan, Zheng 
791d8f8360SYan, Zheng 	memcpy(&ent->fsid, fsid, sizeof(*fsid));
801d8f8360SYan, Zheng 	if (uniq_len > 0) {
811d8f8360SYan, Zheng 		memcpy(&ent->uniquifier, fscache_uniq, uniq_len);
821d8f8360SYan, Zheng 		ent->uniq_len = uniq_len;
831d8f8360SYan, Zheng 	}
84402cb8ddSDavid Howells 
85402cb8ddSDavid Howells 	fsc->fscache = fscache_acquire_cookie(ceph_cache_netfs.primary_index,
86402cb8ddSDavid Howells 					      &ceph_fscache_fsid_object_def,
87402cb8ddSDavid Howells 					      &ent->fsid, sizeof(ent->fsid) + uniq_len,
88402cb8ddSDavid Howells 					      NULL, 0,
89ee1235a9SDavid Howells 					      fsc, 0, true);
90402cb8ddSDavid Howells 
91402cb8ddSDavid Howells 	if (fsc->fscache) {
921d8f8360SYan, Zheng 		ent->fscache = fsc->fscache;
931d8f8360SYan, Zheng 		list_add_tail(&ent->list, &ceph_fscache_list);
941d8f8360SYan, Zheng 	} else {
951d8f8360SYan, Zheng 		kfree(ent);
961d8f8360SYan, Zheng 		pr_err("unable to register fscache cookie for fsid %pU\n",
971d8f8360SYan, Zheng 		       fsid);
981d8f8360SYan, Zheng 		/* all other fs ignore this error */
991d8f8360SYan, Zheng 	}
1001d8f8360SYan, Zheng out_unlock:
1011d8f8360SYan, Zheng 	mutex_unlock(&ceph_fscache_lock);
1021d8f8360SYan, Zheng 	return err;
10399ccbd22SMilosz Tanski }
10499ccbd22SMilosz Tanski 
10599ccbd22SMilosz Tanski static enum fscache_checkaux ceph_fscache_inode_check_aux(
106ee1235a9SDavid Howells 	void *cookie_netfs_data, const void *data, uint16_t dlen,
107ee1235a9SDavid Howells 	loff_t object_size)
10899ccbd22SMilosz Tanski {
10999ccbd22SMilosz Tanski 	struct ceph_aux_inode aux;
11099ccbd22SMilosz Tanski 	struct ceph_inode_info* ci = cookie_netfs_data;
11199ccbd22SMilosz Tanski 	struct inode* inode = &ci->vfs_inode;
11299ccbd22SMilosz Tanski 
113ee1235a9SDavid Howells 	if (dlen != sizeof(aux) ||
114ee1235a9SDavid Howells 	    i_size_read(inode) != object_size)
11599ccbd22SMilosz Tanski 		return FSCACHE_CHECKAUX_OBSOLETE;
11699ccbd22SMilosz Tanski 
11799ccbd22SMilosz Tanski 	memset(&aux, 0, sizeof(aux));
118f6973c09SYan, Zheng 	aux.version = ci->i_version;
1199bbeab41SArnd Bergmann 	aux.mtime_sec = inode->i_mtime.tv_sec;
1209bbeab41SArnd Bergmann 	aux.mtime_nsec = inode->i_mtime.tv_nsec;
12199ccbd22SMilosz Tanski 
12299ccbd22SMilosz Tanski 	if (memcmp(data, &aux, sizeof(aux)) != 0)
12399ccbd22SMilosz Tanski 		return FSCACHE_CHECKAUX_OBSOLETE;
12499ccbd22SMilosz Tanski 
1254c069a58SChengguang Xu 	dout("ceph inode 0x%p cached okay\n", ci);
12699ccbd22SMilosz Tanski 	return FSCACHE_CHECKAUX_OKAY;
12799ccbd22SMilosz Tanski }
12899ccbd22SMilosz Tanski 
12999ccbd22SMilosz Tanski static const struct fscache_cookie_def ceph_fscache_inode_object_def = {
13099ccbd22SMilosz Tanski 	.name		= "CEPH.inode",
13199ccbd22SMilosz Tanski 	.type		= FSCACHE_COOKIE_TYPE_DATAFILE,
13299ccbd22SMilosz Tanski 	.check_aux	= ceph_fscache_inode_check_aux,
13399ccbd22SMilosz Tanski };
13499ccbd22SMilosz Tanski 
13546b59b2bSYan, Zheng void ceph_fscache_register_inode_cookie(struct inode *inode)
13699ccbd22SMilosz Tanski {
13746b59b2bSYan, Zheng 	struct ceph_inode_info *ci = ceph_inode(inode);
13846b59b2bSYan, Zheng 	struct ceph_fs_client *fsc = ceph_inode_to_client(inode);
139402cb8ddSDavid Howells 	struct ceph_aux_inode aux;
14099ccbd22SMilosz Tanski 
14199ccbd22SMilosz Tanski 	/* No caching for filesystem */
142d37b1d99SMarkus Elfring 	if (!fsc->fscache)
14399ccbd22SMilosz Tanski 		return;
14499ccbd22SMilosz Tanski 
14599ccbd22SMilosz Tanski 	/* Only cache for regular files that are read only */
14646b59b2bSYan, Zheng 	if (!S_ISREG(inode->i_mode))
14799ccbd22SMilosz Tanski 		return;
14899ccbd22SMilosz Tanski 
14946b59b2bSYan, Zheng 	inode_lock_nested(inode, I_MUTEX_CHILD);
15046b59b2bSYan, Zheng 	if (!ci->fscache) {
151402cb8ddSDavid Howells 		memset(&aux, 0, sizeof(aux));
152402cb8ddSDavid Howells 		aux.version = ci->i_version;
1539bbeab41SArnd Bergmann 		aux.mtime_sec = inode->i_mtime.tv_sec;
1549bbeab41SArnd Bergmann 		aux.mtime_nsec = inode->i_mtime.tv_nsec;
15599ccbd22SMilosz Tanski 		ci->fscache = fscache_acquire_cookie(fsc->fscache,
15699ccbd22SMilosz Tanski 						     &ceph_fscache_inode_object_def,
157402cb8ddSDavid Howells 						     &ci->i_vino, sizeof(ci->i_vino),
158402cb8ddSDavid Howells 						     &aux, sizeof(aux),
159ee1235a9SDavid Howells 						     ci, i_size_read(inode), false);
16046b59b2bSYan, Zheng 	}
1615955102cSAl Viro 	inode_unlock(inode);
16299ccbd22SMilosz Tanski }
16399ccbd22SMilosz Tanski 
16499ccbd22SMilosz Tanski void ceph_fscache_unregister_inode_cookie(struct ceph_inode_info* ci)
16599ccbd22SMilosz Tanski {
16699ccbd22SMilosz Tanski 	struct fscache_cookie* cookie;
16799ccbd22SMilosz Tanski 
16899ccbd22SMilosz Tanski 	if ((cookie = ci->fscache) == NULL)
16999ccbd22SMilosz Tanski 		return;
17099ccbd22SMilosz Tanski 
17199ccbd22SMilosz Tanski 	ci->fscache = NULL;
17299ccbd22SMilosz Tanski 
17399ccbd22SMilosz Tanski 	fscache_uncache_all_inode_pages(cookie, &ci->vfs_inode);
174402cb8ddSDavid Howells 	fscache_relinquish_cookie(cookie, &ci->i_vino, false);
17599ccbd22SMilosz Tanski }
17699ccbd22SMilosz Tanski 
17746b59b2bSYan, Zheng static bool ceph_fscache_can_enable(void *data)
17846b59b2bSYan, Zheng {
17946b59b2bSYan, Zheng 	struct inode *inode = data;
18046b59b2bSYan, Zheng 	return !inode_is_open_for_write(inode);
18146b59b2bSYan, Zheng }
18246b59b2bSYan, Zheng 
18346b59b2bSYan, Zheng void ceph_fscache_file_set_cookie(struct inode *inode, struct file *filp)
18446b59b2bSYan, Zheng {
18546b59b2bSYan, Zheng 	struct ceph_inode_info *ci = ceph_inode(inode);
18646b59b2bSYan, Zheng 
18746b59b2bSYan, Zheng 	if (!fscache_cookie_valid(ci->fscache))
18846b59b2bSYan, Zheng 		return;
18946b59b2bSYan, Zheng 
19046b59b2bSYan, Zheng 	if (inode_is_open_for_write(inode)) {
19146b59b2bSYan, Zheng 		dout("fscache_file_set_cookie %p %p disabling cache\n",
19246b59b2bSYan, Zheng 		     inode, filp);
193402cb8ddSDavid Howells 		fscache_disable_cookie(ci->fscache, &ci->i_vino, false);
19446b59b2bSYan, Zheng 		fscache_uncache_all_inode_pages(ci->fscache, inode);
19546b59b2bSYan, Zheng 	} else {
196ee1235a9SDavid Howells 		fscache_enable_cookie(ci->fscache, &ci->i_vino, i_size_read(inode),
197402cb8ddSDavid Howells 				      ceph_fscache_can_enable, inode);
19846b59b2bSYan, Zheng 		if (fscache_cookie_enabled(ci->fscache)) {
1990fbc5360SColin Ian King 			dout("fscache_file_set_cookie %p %p enabling cache\n",
20046b59b2bSYan, Zheng 			     inode, filp);
20146b59b2bSYan, Zheng 		}
20246b59b2bSYan, Zheng 	}
20346b59b2bSYan, Zheng }
20446b59b2bSYan, Zheng 
205dd2bc473SYan, Zheng static void ceph_readpage_from_fscache_complete(struct page *page, void *data, int error)
20699ccbd22SMilosz Tanski {
20799ccbd22SMilosz Tanski 	if (!error)
20899ccbd22SMilosz Tanski 		SetPageUptodate(page);
20999ccbd22SMilosz Tanski 
21099ccbd22SMilosz Tanski 	unlock_page(page);
21199ccbd22SMilosz Tanski }
21299ccbd22SMilosz Tanski 
2133b33f692SZhang Zhuoyu static inline bool cache_valid(struct ceph_inode_info *ci)
21499ccbd22SMilosz Tanski {
215f7f7e7a0SYan, Zheng 	return ci->i_fscache_gen == ci->i_rdcache_gen;
21699ccbd22SMilosz Tanski }
21799ccbd22SMilosz Tanski 
21899ccbd22SMilosz Tanski 
21999ccbd22SMilosz Tanski /* Atempt to read from the fscache,
22099ccbd22SMilosz Tanski  *
22199ccbd22SMilosz Tanski  * This function is called from the readpage_nounlock context. DO NOT attempt to
22299ccbd22SMilosz Tanski  * unlock the page here (or in the callback).
22399ccbd22SMilosz Tanski  */
22499ccbd22SMilosz Tanski int ceph_readpage_from_fscache(struct inode *inode, struct page *page)
22599ccbd22SMilosz Tanski {
22699ccbd22SMilosz Tanski 	struct ceph_inode_info *ci = ceph_inode(inode);
22799ccbd22SMilosz Tanski 	int ret;
22899ccbd22SMilosz Tanski 
22999ccbd22SMilosz Tanski 	if (!cache_valid(ci))
23099ccbd22SMilosz Tanski 		return -ENOBUFS;
23199ccbd22SMilosz Tanski 
23299ccbd22SMilosz Tanski 	ret = fscache_read_or_alloc_page(ci->fscache, page,
233dd2bc473SYan, Zheng 					 ceph_readpage_from_fscache_complete, NULL,
23499ccbd22SMilosz Tanski 					 GFP_KERNEL);
23599ccbd22SMilosz Tanski 
23699ccbd22SMilosz Tanski 	switch (ret) {
23799ccbd22SMilosz Tanski 		case 0: /* Page found */
23899ccbd22SMilosz Tanski 			dout("page read submitted\n");
23999ccbd22SMilosz Tanski 			return 0;
24099ccbd22SMilosz Tanski 		case -ENOBUFS: /* Pages were not found, and can't be */
24199ccbd22SMilosz Tanski 		case -ENODATA: /* Pages were not found */
24299ccbd22SMilosz Tanski 			dout("page/inode not in cache\n");
24399ccbd22SMilosz Tanski 			return ret;
24499ccbd22SMilosz Tanski 		default:
24599ccbd22SMilosz Tanski 			dout("%s: unknown error ret = %i\n", __func__, ret);
24699ccbd22SMilosz Tanski 			return ret;
24799ccbd22SMilosz Tanski 	}
24899ccbd22SMilosz Tanski }
24999ccbd22SMilosz Tanski 
25099ccbd22SMilosz Tanski int ceph_readpages_from_fscache(struct inode *inode,
25199ccbd22SMilosz Tanski 				  struct address_space *mapping,
25299ccbd22SMilosz Tanski 				  struct list_head *pages,
25399ccbd22SMilosz Tanski 				  unsigned *nr_pages)
25499ccbd22SMilosz Tanski {
25599ccbd22SMilosz Tanski 	struct ceph_inode_info *ci = ceph_inode(inode);
25699ccbd22SMilosz Tanski 	int ret;
25799ccbd22SMilosz Tanski 
25899ccbd22SMilosz Tanski 	if (!cache_valid(ci))
25999ccbd22SMilosz Tanski 		return -ENOBUFS;
26099ccbd22SMilosz Tanski 
26199ccbd22SMilosz Tanski 	ret = fscache_read_or_alloc_pages(ci->fscache, mapping, pages, nr_pages,
262dd2bc473SYan, Zheng 					  ceph_readpage_from_fscache_complete,
26399ccbd22SMilosz Tanski 					  NULL, mapping_gfp_mask(mapping));
26499ccbd22SMilosz Tanski 
26599ccbd22SMilosz Tanski 	switch (ret) {
26699ccbd22SMilosz Tanski 		case 0: /* All pages found */
26799ccbd22SMilosz Tanski 			dout("all-page read submitted\n");
26899ccbd22SMilosz Tanski 			return 0;
26999ccbd22SMilosz Tanski 		case -ENOBUFS: /* Some pages were not found, and can't be */
27099ccbd22SMilosz Tanski 		case -ENODATA: /* some pages were not found */
27199ccbd22SMilosz Tanski 			dout("page/inode not in cache\n");
27299ccbd22SMilosz Tanski 			return ret;
27399ccbd22SMilosz Tanski 		default:
27499ccbd22SMilosz Tanski 			dout("%s: unknown error ret = %i\n", __func__, ret);
27599ccbd22SMilosz Tanski 			return ret;
27699ccbd22SMilosz Tanski 	}
27799ccbd22SMilosz Tanski }
27899ccbd22SMilosz Tanski 
27999ccbd22SMilosz Tanski void ceph_readpage_to_fscache(struct inode *inode, struct page *page)
28099ccbd22SMilosz Tanski {
28199ccbd22SMilosz Tanski 	struct ceph_inode_info *ci = ceph_inode(inode);
28299ccbd22SMilosz Tanski 	int ret;
28399ccbd22SMilosz Tanski 
2849b8dd1e8SMilosz Tanski 	if (!PageFsCache(page))
2859b8dd1e8SMilosz Tanski 		return;
2869b8dd1e8SMilosz Tanski 
28799ccbd22SMilosz Tanski 	if (!cache_valid(ci))
28899ccbd22SMilosz Tanski 		return;
28999ccbd22SMilosz Tanski 
290ee1235a9SDavid Howells 	ret = fscache_write_page(ci->fscache, page, i_size_read(inode),
291ee1235a9SDavid Howells 				 GFP_KERNEL);
29299ccbd22SMilosz Tanski 	if (ret)
29399ccbd22SMilosz Tanski 		 fscache_uncache_page(ci->fscache, page);
29499ccbd22SMilosz Tanski }
29599ccbd22SMilosz Tanski 
29699ccbd22SMilosz Tanski void ceph_invalidate_fscache_page(struct inode* inode, struct page *page)
29799ccbd22SMilosz Tanski {
29899ccbd22SMilosz Tanski 	struct ceph_inode_info *ci = ceph_inode(inode);
29999ccbd22SMilosz Tanski 
300ffc79664SMilosz Tanski 	if (!PageFsCache(page))
301ffc79664SMilosz Tanski 		return;
302ffc79664SMilosz Tanski 
30399ccbd22SMilosz Tanski 	fscache_wait_on_page_write(ci->fscache, page);
30499ccbd22SMilosz Tanski 	fscache_uncache_page(ci->fscache, page);
30599ccbd22SMilosz Tanski }
30699ccbd22SMilosz Tanski 
30799ccbd22SMilosz Tanski void ceph_fscache_unregister_fs(struct ceph_fs_client* fsc)
30899ccbd22SMilosz Tanski {
3091d8f8360SYan, Zheng 	if (fscache_cookie_valid(fsc->fscache)) {
3101d8f8360SYan, Zheng 		struct ceph_fscache_entry *ent;
3111d8f8360SYan, Zheng 		bool found = false;
3121d8f8360SYan, Zheng 
3131d8f8360SYan, Zheng 		mutex_lock(&ceph_fscache_lock);
3141d8f8360SYan, Zheng 		list_for_each_entry(ent, &ceph_fscache_list, list) {
3151d8f8360SYan, Zheng 			if (ent->fscache == fsc->fscache) {
3161d8f8360SYan, Zheng 				list_del(&ent->list);
3171d8f8360SYan, Zheng 				kfree(ent);
3181d8f8360SYan, Zheng 				found = true;
3191d8f8360SYan, Zheng 				break;
3201d8f8360SYan, Zheng 			}
3211d8f8360SYan, Zheng 		}
3221d8f8360SYan, Zheng 		WARN_ON_ONCE(!found);
3231d8f8360SYan, Zheng 		mutex_unlock(&ceph_fscache_lock);
3241d8f8360SYan, Zheng 
325402cb8ddSDavid Howells 		__fscache_relinquish_cookie(fsc->fscache, NULL, false);
3261d8f8360SYan, Zheng 	}
32799ccbd22SMilosz Tanski 	fsc->fscache = NULL;
32899ccbd22SMilosz Tanski }
32999ccbd22SMilosz Tanski 
330f7f7e7a0SYan, Zheng /*
331f7f7e7a0SYan, Zheng  * caller should hold CEPH_CAP_FILE_{RD,CACHE}
332f7f7e7a0SYan, Zheng  */
333f7f7e7a0SYan, Zheng void ceph_fscache_revalidate_cookie(struct ceph_inode_info *ci)
33499ccbd22SMilosz Tanski {
335f7f7e7a0SYan, Zheng 	if (cache_valid(ci))
336e81568ebSMilosz Tanski 		return;
337e81568ebSMilosz Tanski 
338f7f7e7a0SYan, Zheng 	/* resue i_truncate_mutex. There should be no pending
339f7f7e7a0SYan, Zheng 	 * truncate while the caller holds CEPH_CAP_FILE_RD */
340f7f7e7a0SYan, Zheng 	mutex_lock(&ci->i_truncate_mutex);
341f7f7e7a0SYan, Zheng 	if (!cache_valid(ci)) {
342402cb8ddSDavid Howells 		if (fscache_check_consistency(ci->fscache, &ci->i_vino))
343f7f7e7a0SYan, Zheng 			fscache_invalidate(ci->fscache);
344f7f7e7a0SYan, Zheng 		spin_lock(&ci->i_ceph_lock);
345f7f7e7a0SYan, Zheng 		ci->i_fscache_gen = ci->i_rdcache_gen;
346f7f7e7a0SYan, Zheng 		spin_unlock(&ci->i_ceph_lock);
34799ccbd22SMilosz Tanski 	}
348f7f7e7a0SYan, Zheng 	mutex_unlock(&ci->i_truncate_mutex);
34999ccbd22SMilosz Tanski }
350