Linux Audio

Check our new training course

Linux BSP development engineering services

Need help to port Linux and bootloaders to your hardware?
Loading...
v6.2
  1// SPDX-License-Identifier: LGPL-2.1
  2/*
  3 *   CIFS filesystem cache interface
  4 *
  5 *   Copyright (c) 2010 Novell, Inc.
  6 *   Author(s): Suresh Jayaraman <sjayaraman@suse.de>
  7 *
 
 
 
 
 
 
 
 
 
 
 
 
 
  8 */
  9#include "fscache.h"
 10#include "cifsglob.h"
 11#include "cifs_debug.h"
 12#include "cifs_fs_sb.h"
 13#include "cifsproto.h"
 14
 15static void cifs_fscache_fill_volume_coherency(
 16	struct cifs_tcon *tcon,
 17	struct cifs_fscache_volume_coherency_data *cd)
 18{
 19	memset(cd, 0, sizeof(*cd));
 20	cd->resource_id		= cpu_to_le64(tcon->resource_id);
 21	cd->vol_create_time	= tcon->vol_create_time;
 22	cd->vol_serial_number	= cpu_to_le32(tcon->vol_serial_number);
 23}
 
 
 
 
 24
 25int cifs_fscache_get_super_cookie(struct cifs_tcon *tcon)
 
 
 
 26{
 27	struct cifs_fscache_volume_coherency_data cd;
 28	struct TCP_Server_Info *server = tcon->ses->server;
 29	struct fscache_volume *vcookie;
 30	const struct sockaddr *sa = (struct sockaddr *)&server->dstaddr;
 31	size_t slen, i;
 32	char *sharename;
 33	char *key;
 34	int ret = -ENOMEM;
 35
 36	tcon->fscache = NULL;
 
 
 
 
 
 
 37	switch (sa->sa_family) {
 38	case AF_INET:
 
 
 
 
 
 39	case AF_INET6:
 
 
 
 40		break;
 
 41	default:
 42		cifs_dbg(VFS, "Unknown network family '%d'\n", sa->sa_family);
 43		return -EINVAL;
 
 44	}
 45
 46	memset(&key, 0, sizeof(key));
 
 
 
 
 
 
 
 
 47
 48	sharename = extract_sharename(tcon->tree_name);
 
 
 
 
 
 
 
 
 
 
 
 
 
 49	if (IS_ERR(sharename)) {
 50		cifs_dbg(FYI, "%s: couldn't extract sharename\n", __func__);
 51		return -EINVAL;
 
 52	}
 53
 54	slen = strlen(sharename);
 55	for (i = 0; i < slen; i++)
 56		if (sharename[i] == '/')
 57			sharename[i] = ';';
 58
 59	key = kasprintf(GFP_KERNEL, "cifs,%pISpc,%s", sa, sharename);
 60	if (!key)
 61		goto out;
 62
 63	cifs_fscache_fill_volume_coherency(tcon, &cd);
 64	vcookie = fscache_acquire_volume(key,
 65					 NULL, /* preferred_cache */
 66					 &cd, sizeof(cd));
 67	cifs_dbg(FYI, "%s: (%s/0x%p)\n", __func__, key, vcookie);
 68	if (IS_ERR(vcookie)) {
 69		if (vcookie != ERR_PTR(-EBUSY)) {
 70			ret = PTR_ERR(vcookie);
 71			goto out_2;
 72		}
 73		pr_err("Cache volume key already in use (%s)\n", key);
 74		vcookie = NULL;
 75	}
 76
 77	tcon->fscache = vcookie;
 78	ret = 0;
 79out_2:
 80	kfree(key);
 81out:
 82	kfree(sharename);
 83	return ret;
 
 84}
 85
 86void cifs_fscache_release_super_cookie(struct cifs_tcon *tcon)
 87{
 88	struct cifs_fscache_volume_coherency_data cd;
 89
 90	cifs_dbg(FYI, "%s: (0x%p)\n", __func__, tcon->fscache);
 91
 92	cifs_fscache_fill_volume_coherency(tcon, &cd);
 93	fscache_relinquish_volume(tcon->fscache, &cd, false);
 94	tcon->fscache = NULL;
 95}
 96
 97void cifs_fscache_get_inode_cookie(struct inode *inode)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 98{
 99	struct cifs_fscache_inode_coherency_data cd;
100	struct cifsInodeInfo *cifsi = CIFS_I(inode);
101	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
102	struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
103
104	cifs_fscache_fill_coherency(&cifsi->netfs.inode, &cd);
 
105
106	cifsi->netfs.cache =
107		fscache_acquire_cookie(tcon->fscache, 0,
108				       &cifsi->uniqueid, sizeof(cifsi->uniqueid),
109				       &cd, sizeof(cd),
110				       i_size_read(&cifsi->netfs.inode));
 
 
111}
112
113void cifs_fscache_unuse_inode_cookie(struct inode *inode, bool update)
114{
115	if (update) {
116		struct cifs_fscache_inode_coherency_data cd;
117		loff_t i_size = i_size_read(inode);
118
119		cifs_fscache_fill_coherency(inode, &cd);
120		fscache_unuse_cookie(cifs_inode_cookie(inode), &cd, &i_size);
121	} else {
122		fscache_unuse_cookie(cifs_inode_cookie(inode), NULL, NULL);
 
 
 
 
 
 
 
123	}
124}
125
126void cifs_fscache_release_inode_cookie(struct inode *inode)
127{
128	struct cifsInodeInfo *cifsi = CIFS_I(inode);
129	struct fscache_cookie *cookie = cifs_inode_cookie(inode);
130
131	if (cookie) {
132		cifs_dbg(FYI, "%s: (0x%p)\n", __func__, cookie);
133		fscache_relinquish_cookie(cookie, false);
134		cifsi->netfs.cache = NULL;
 
135	}
136}
137
138/*
139 * Fallback page reading interface.
140 */
141static int fscache_fallback_read_page(struct inode *inode, struct page *page)
142{
143	struct netfs_cache_resources cres;
144	struct fscache_cookie *cookie = cifs_inode_cookie(inode);
145	struct iov_iter iter;
146	struct bio_vec bvec[1];
147	int ret;
148
149	memset(&cres, 0, sizeof(cres));
150	bvec[0].bv_page		= page;
151	bvec[0].bv_offset	= 0;
152	bvec[0].bv_len		= PAGE_SIZE;
153	iov_iter_bvec(&iter, ITER_DEST, bvec, ARRAY_SIZE(bvec), PAGE_SIZE);
 
154
155	ret = fscache_begin_read_operation(&cres, cookie);
156	if (ret < 0)
157		return ret;
 
 
 
 
 
 
158
159	ret = fscache_read(&cres, page_offset(page), &iter, NETFS_READ_HOLE_FAIL,
160			   NULL, NULL);
161	fscache_end_operation(&cres);
162	return ret;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
163}
164
165/*
166 * Fallback page writing interface.
167 */
168static int fscache_fallback_write_page(struct inode *inode, struct page *page,
169				       bool no_space_allocated_yet)
170{
171	struct netfs_cache_resources cres;
172	struct fscache_cookie *cookie = cifs_inode_cookie(inode);
173	struct iov_iter iter;
174	struct bio_vec bvec[1];
175	loff_t start = page_offset(page);
176	size_t len = PAGE_SIZE;
177	int ret;
178
179	memset(&cres, 0, sizeof(cres));
180	bvec[0].bv_page		= page;
181	bvec[0].bv_offset	= 0;
182	bvec[0].bv_len		= PAGE_SIZE;
183	iov_iter_bvec(&iter, ITER_SOURCE, bvec, ARRAY_SIZE(bvec), PAGE_SIZE);
 
 
184
185	ret = fscache_begin_write_operation(&cres, cookie);
186	if (ret < 0)
187		return ret;
 
 
 
 
188
189	ret = cres.ops->prepare_write(&cres, &start, &len, i_size_read(inode),
190				      no_space_allocated_yet);
191	if (ret == 0)
192		ret = fscache_write(&cres, page_offset(page), &iter, NULL, NULL);
193	fscache_end_operation(&cres);
194	return ret;
195}
196
197/*
198 * Retrieve a page from FS-Cache
199 */
200int __cifs_readpage_from_fscache(struct inode *inode, struct page *page)
 
 
 
201{
202	int ret;
203
204	cifs_dbg(FYI, "%s: (fsc:%p, p:%p, i:0x%p\n",
205		 __func__, cifs_inode_cookie(inode), page, inode);
206
207	ret = fscache_fallback_read_page(inode, page);
208	if (ret < 0)
 
 
 
 
 
209		return ret;
210
211	/* Read completed synchronously */
212	SetPageUptodate(page);
213	return 0;
 
 
 
 
 
 
 
214}
215
216void __cifs_readpage_to_fscache(struct inode *inode, struct page *page)
217{
218	cifs_dbg(FYI, "%s: (fsc: %p, p: %p, i: %p)\n",
219		 __func__, cifs_inode_cookie(inode), page, inode);
220
221	fscache_fallback_write_page(inode, page, true);
 
 
 
 
 
222}
223
224/*
225 * Query the cache occupancy.
226 */
227int __cifs_fscache_query_occupancy(struct inode *inode,
228				   pgoff_t first, unsigned int nr_pages,
229				   pgoff_t *_data_first,
230				   unsigned int *_data_nr_pages)
231{
232	struct netfs_cache_resources cres;
233	struct fscache_cookie *cookie = cifs_inode_cookie(inode);
234	loff_t start, data_start;
235	size_t len, data_len;
236	int ret;
237
238	ret = fscache_begin_read_operation(&cres, cookie);
239	if (ret < 0)
240		return ret;
241
242	start = first * PAGE_SIZE;
243	len = nr_pages * PAGE_SIZE;
244	ret = cres.ops->query_occupancy(&cres, start, len, PAGE_SIZE,
245					&data_start, &data_len);
246	if (ret == 0) {
247		*_data_first = data_start / PAGE_SIZE;
248		*_data_nr_pages = len / PAGE_SIZE;
249	}
250
251	fscache_end_operation(&cres);
252	return ret;
 
253}
v5.4
 
  1/*
  2 *   fs/cifs/fscache.c - CIFS filesystem cache interface
  3 *
  4 *   Copyright (c) 2010 Novell, Inc.
  5 *   Author(s): Suresh Jayaraman <sjayaraman@suse.de>
  6 *
  7 *   This library is free software; you can redistribute it and/or modify
  8 *   it under the terms of the GNU Lesser General Public License as published
  9 *   by the Free Software Foundation; either version 2.1 of the License, or
 10 *   (at your option) any later version.
 11 *
 12 *   This library is distributed in the hope that it will be useful,
 13 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 14 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
 15 *   the GNU Lesser General Public License for more details.
 16 *
 17 *   You should have received a copy of the GNU Lesser General Public License
 18 *   along with this library; if not, write to the Free Software
 19 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 20 */
 21#include "fscache.h"
 22#include "cifsglob.h"
 23#include "cifs_debug.h"
 24#include "cifs_fs_sb.h"
 
 25
 26/*
 27 * Key layout of CIFS server cache index object
 28 */
 29struct cifs_server_key {
 30	struct {
 31		uint16_t	family;		/* address family */
 32		__be16		port;		/* IP port */
 33	} hdr;
 34	union {
 35		struct in_addr	ipv4_addr;
 36		struct in6_addr	ipv6_addr;
 37	};
 38} __packed;
 39
 40/*
 41 * Get a cookie for a server object keyed by {IPaddress,port,family} tuple
 42 */
 43void cifs_fscache_get_client_cookie(struct TCP_Server_Info *server)
 44{
 45	const struct sockaddr *sa = (struct sockaddr *) &server->dstaddr;
 46	const struct sockaddr_in *addr = (struct sockaddr_in *) sa;
 47	const struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) sa;
 48	struct cifs_server_key key;
 49	uint16_t key_len = sizeof(key.hdr);
 
 
 
 50
 51	memset(&key, 0, sizeof(key));
 52
 53	/*
 54	 * Should not be a problem as sin_family/sin6_family overlays
 55	 * sa_family field
 56	 */
 57	key.hdr.family = sa->sa_family;
 58	switch (sa->sa_family) {
 59	case AF_INET:
 60		key.hdr.port = addr->sin_port;
 61		key.ipv4_addr = addr->sin_addr;
 62		key_len += sizeof(key.ipv4_addr);
 63		break;
 64
 65	case AF_INET6:
 66		key.hdr.port = addr6->sin6_port;
 67		key.ipv6_addr = addr6->sin6_addr;
 68		key_len += sizeof(key.ipv6_addr);
 69		break;
 70
 71	default:
 72		cifs_dbg(VFS, "Unknown network family '%d'\n", sa->sa_family);
 73		server->fscache = NULL;
 74		return;
 75	}
 76
 77	server->fscache =
 78		fscache_acquire_cookie(cifs_fscache_netfs.primary_index,
 79				       &cifs_fscache_server_index_def,
 80				       &key, key_len,
 81				       NULL, 0,
 82				       server, 0, true);
 83	cifs_dbg(FYI, "%s: (0x%p/0x%p)\n",
 84		 __func__, server, server->fscache);
 85}
 86
 87void cifs_fscache_release_client_cookie(struct TCP_Server_Info *server)
 88{
 89	cifs_dbg(FYI, "%s: (0x%p/0x%p)\n",
 90		 __func__, server, server->fscache);
 91	fscache_relinquish_cookie(server->fscache, NULL, false);
 92	server->fscache = NULL;
 93}
 94
 95void cifs_fscache_get_super_cookie(struct cifs_tcon *tcon)
 96{
 97	struct TCP_Server_Info *server = tcon->ses->server;
 98	char *sharename;
 99
100	sharename = extract_sharename(tcon->treeName);
101	if (IS_ERR(sharename)) {
102		cifs_dbg(FYI, "%s: couldn't extract sharename\n", __func__);
103		tcon->fscache = NULL;
104		return;
105	}
106
107	tcon->fscache =
108		fscache_acquire_cookie(server->fscache,
109				       &cifs_fscache_super_index_def,
110				       sharename, strlen(sharename),
111				       &tcon->resource_id, sizeof(tcon->resource_id),
112				       tcon, 0, true);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
113	kfree(sharename);
114	cifs_dbg(FYI, "%s: (0x%p/0x%p)\n",
115		 __func__, server->fscache, tcon->fscache);
116}
117
118void cifs_fscache_release_super_cookie(struct cifs_tcon *tcon)
119{
 
 
120	cifs_dbg(FYI, "%s: (0x%p)\n", __func__, tcon->fscache);
121	fscache_relinquish_cookie(tcon->fscache, &tcon->resource_id, false);
 
 
122	tcon->fscache = NULL;
123}
124
125static void cifs_fscache_acquire_inode_cookie(struct cifsInodeInfo *cifsi,
126					      struct cifs_tcon *tcon)
127{
128	struct cifs_fscache_inode_auxdata auxdata;
129
130	memset(&auxdata, 0, sizeof(auxdata));
131	auxdata.eof = cifsi->server_eof;
132	auxdata.last_write_time_sec = cifsi->vfs_inode.i_mtime.tv_sec;
133	auxdata.last_change_time_sec = cifsi->vfs_inode.i_ctime.tv_sec;
134	auxdata.last_write_time_nsec = cifsi->vfs_inode.i_mtime.tv_nsec;
135	auxdata.last_change_time_nsec = cifsi->vfs_inode.i_ctime.tv_nsec;
136
137	cifsi->fscache =
138		fscache_acquire_cookie(tcon->fscache,
139				       &cifs_fscache_inode_object_def,
140				       &cifsi->uniqueid, sizeof(cifsi->uniqueid),
141				       &auxdata, sizeof(auxdata),
142				       cifsi, cifsi->vfs_inode.i_size, true);
143}
144
145static void cifs_fscache_enable_inode_cookie(struct inode *inode)
146{
 
147	struct cifsInodeInfo *cifsi = CIFS_I(inode);
148	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
149	struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
150
151	if (cifsi->fscache)
152		return;
153
154	if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_FSCACHE))
155		return;
156
157	cifs_fscache_acquire_inode_cookie(cifsi, tcon);
158
159	cifs_dbg(FYI, "%s: got FH cookie (0x%p/0x%p)\n",
160		 __func__, tcon->fscache, cifsi->fscache);
161}
162
163void cifs_fscache_release_inode_cookie(struct inode *inode)
164{
165	struct cifs_fscache_inode_auxdata auxdata;
166	struct cifsInodeInfo *cifsi = CIFS_I(inode);
 
167
168	if (cifsi->fscache) {
169		memset(&auxdata, 0, sizeof(auxdata));
170		auxdata.eof = cifsi->server_eof;
171		auxdata.last_write_time_sec = cifsi->vfs_inode.i_mtime.tv_sec;
172		auxdata.last_change_time_sec = cifsi->vfs_inode.i_ctime.tv_sec;
173		auxdata.last_write_time_nsec = cifsi->vfs_inode.i_mtime.tv_nsec;
174		auxdata.last_change_time_nsec = cifsi->vfs_inode.i_ctime.tv_nsec;
175
176		cifs_dbg(FYI, "%s: (0x%p)\n", __func__, cifsi->fscache);
177		fscache_relinquish_cookie(cifsi->fscache, &auxdata, false);
178		cifsi->fscache = NULL;
179	}
180}
181
182static void cifs_fscache_disable_inode_cookie(struct inode *inode)
183{
184	struct cifsInodeInfo *cifsi = CIFS_I(inode);
 
185
186	if (cifsi->fscache) {
187		cifs_dbg(FYI, "%s: (0x%p)\n", __func__, cifsi->fscache);
188		fscache_uncache_all_inode_pages(cifsi->fscache, inode);
189		fscache_relinquish_cookie(cifsi->fscache, NULL, true);
190		cifsi->fscache = NULL;
191	}
192}
193
194void cifs_fscache_set_inode_cookie(struct inode *inode, struct file *filp)
 
 
 
195{
196	if ((filp->f_flags & O_ACCMODE) != O_RDONLY)
197		cifs_fscache_disable_inode_cookie(inode);
198	else
199		cifs_fscache_enable_inode_cookie(inode);
200}
201
202void cifs_fscache_reset_inode_cookie(struct inode *inode)
203{
204	struct cifsInodeInfo *cifsi = CIFS_I(inode);
205	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
206	struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
207	struct fscache_cookie *old = cifsi->fscache;
208
209	if (cifsi->fscache) {
210		/* retire the current fscache cache and get a new one */
211		fscache_relinquish_cookie(cifsi->fscache, NULL, true);
212
213		cifs_fscache_acquire_inode_cookie(cifsi, tcon);
214		cifs_dbg(FYI, "%s: new cookie 0x%p oldcookie 0x%p\n",
215			 __func__, cifsi->fscache, old);
216	}
217}
218
219int cifs_fscache_release_page(struct page *page, gfp_t gfp)
220{
221	if (PageFsCache(page)) {
222		struct inode *inode = page->mapping->host;
223		struct cifsInodeInfo *cifsi = CIFS_I(inode);
224
225		cifs_dbg(FYI, "%s: (0x%p/0x%p)\n",
226			 __func__, page, cifsi->fscache);
227		if (!fscache_maybe_release_page(cifsi->fscache, page, gfp))
228			return 0;
229	}
230
231	return 1;
232}
233
234static void cifs_readpage_from_fscache_complete(struct page *page, void *ctx,
235						int error)
236{
237	cifs_dbg(FYI, "%s: (0x%p/%d)\n", __func__, page, error);
238	if (!error)
239		SetPageUptodate(page);
240	unlock_page(page);
241}
242
243/*
244 * Retrieve a page from FS-Cache
245 */
246int __cifs_readpage_from_fscache(struct inode *inode, struct page *page)
 
247{
 
 
 
 
 
 
248	int ret;
249
250	cifs_dbg(FYI, "%s: (fsc:%p, p:%p, i:0x%p\n",
251		 __func__, CIFS_I(inode)->fscache, page, inode);
252	ret = fscache_read_or_alloc_page(CIFS_I(inode)->fscache, page,
253					 cifs_readpage_from_fscache_complete,
254					 NULL,
255					 GFP_KERNEL);
256	switch (ret) {
257
258	case 0: /* page found in fscache, read submitted */
259		cifs_dbg(FYI, "%s: submitted\n", __func__);
260		return ret;
261	case -ENOBUFS:	/* page won't be cached */
262	case -ENODATA:	/* page not in cache */
263		cifs_dbg(FYI, "%s: %d\n", __func__, ret);
264		return 1;
265
266	default:
267		cifs_dbg(VFS, "unknown error ret = %d\n", ret);
268	}
 
 
269	return ret;
270}
271
272/*
273 * Retrieve a set of pages from FS-Cache
274 */
275int __cifs_readpages_from_fscache(struct inode *inode,
276				struct address_space *mapping,
277				struct list_head *pages,
278				unsigned *nr_pages)
279{
280	int ret;
281
282	cifs_dbg(FYI, "%s: (0x%p/%u/0x%p)\n",
283		 __func__, CIFS_I(inode)->fscache, *nr_pages, inode);
284	ret = fscache_read_or_alloc_pages(CIFS_I(inode)->fscache, mapping,
285					  pages, nr_pages,
286					  cifs_readpage_from_fscache_complete,
287					  NULL,
288					  mapping_gfp_mask(mapping));
289	switch (ret) {
290	case 0:	/* read submitted to the cache for all pages */
291		cifs_dbg(FYI, "%s: submitted\n", __func__);
292		return ret;
293
294	case -ENOBUFS:	/* some pages are not cached and can't be */
295	case -ENODATA:	/* some pages are not cached */
296		cifs_dbg(FYI, "%s: no page\n", __func__);
297		return 1;
298
299	default:
300		cifs_dbg(FYI, "unknown error ret = %d\n", ret);
301	}
302
303	return ret;
304}
305
306void __cifs_readpage_to_fscache(struct inode *inode, struct page *page)
307{
308	struct cifsInodeInfo *cifsi = CIFS_I(inode);
309	int ret;
310
311	cifs_dbg(FYI, "%s: (fsc: %p, p: %p, i: %p)\n",
312		 __func__, cifsi->fscache, page, inode);
313	ret = fscache_write_page(cifsi->fscache, page,
314				 cifsi->vfs_inode.i_size, GFP_KERNEL);
315	if (ret != 0)
316		fscache_uncache_page(cifsi->fscache, page);
317}
318
319void __cifs_fscache_readpages_cancel(struct inode *inode, struct list_head *pages)
320{
321	cifs_dbg(FYI, "%s: (fsc: %p, i: %p)\n",
322		 __func__, CIFS_I(inode)->fscache, inode);
323	fscache_readpages_cancel(CIFS_I(inode)->fscache, pages);
324}
 
 
 
 
 
 
 
 
 
 
 
325
326void __cifs_fscache_invalidate_page(struct page *page, struct inode *inode)
327{
328	struct cifsInodeInfo *cifsi = CIFS_I(inode);
329	struct fscache_cookie *cookie = cifsi->fscache;
 
 
 
 
330
331	cifs_dbg(FYI, "%s: (0x%p/0x%p)\n", __func__, page, cookie);
332	fscache_wait_on_page_write(cookie, page);
333	fscache_uncache_page(cookie, page);
334}