Linux Audio

Check our new training course

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.14.15
  1// SPDX-License-Identifier: LGPL-2.1
  2/*
  3 *   fs/cifs/fscache.c - 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
 15/*
 16 * Key layout of CIFS server cache index object
 17 */
 18struct cifs_server_key {
 19	struct {
 20		uint16_t	family;		/* address family */
 21		__be16		port;		/* IP port */
 22	} hdr;
 23	union {
 24		struct in_addr	ipv4_addr;
 25		struct in6_addr	ipv6_addr;
 26	};
 27} __packed;
 28
 29/*
 30 * Get a cookie for a server object keyed by {IPaddress,port,family} tuple
 31 */
 32void cifs_fscache_get_client_cookie(struct TCP_Server_Info *server)
 33{
 34	const struct sockaddr *sa = (struct sockaddr *) &server->dstaddr;
 35	const struct sockaddr_in *addr = (struct sockaddr_in *) sa;
 36	const struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) sa;
 37	struct cifs_server_key key;
 38	uint16_t key_len = sizeof(key.hdr);
 
 
 
 39
 40	memset(&key, 0, sizeof(key));
 41
 42	/*
 43	 * Should not be a problem as sin_family/sin6_family overlays
 44	 * sa_family field
 45	 */
 46	key.hdr.family = sa->sa_family;
 47	switch (sa->sa_family) {
 48	case AF_INET:
 49		key.hdr.port = addr->sin_port;
 50		key.ipv4_addr = addr->sin_addr;
 51		key_len += sizeof(key.ipv4_addr);
 52		break;
 53
 54	case AF_INET6:
 55		key.hdr.port = addr6->sin6_port;
 56		key.ipv6_addr = addr6->sin6_addr;
 57		key_len += sizeof(key.ipv6_addr);
 58		break;
 59
 60	default:
 61		cifs_dbg(VFS, "Unknown network family '%d'\n", sa->sa_family);
 62		server->fscache = NULL;
 63		return;
 64	}
 65
 66	server->fscache =
 67		fscache_acquire_cookie(cifs_fscache_netfs.primary_index,
 68				       &cifs_fscache_server_index_def,
 69				       &key, key_len,
 70				       NULL, 0,
 71				       server, 0, true);
 72	cifs_dbg(FYI, "%s: (0x%p/0x%p)\n",
 73		 __func__, server, server->fscache);
 74}
 75
 76void cifs_fscache_release_client_cookie(struct TCP_Server_Info *server)
 77{
 78	cifs_dbg(FYI, "%s: (0x%p/0x%p)\n",
 79		 __func__, server, server->fscache);
 80	fscache_relinquish_cookie(server->fscache, NULL, false);
 81	server->fscache = NULL;
 82}
 83
 84void cifs_fscache_get_super_cookie(struct cifs_tcon *tcon)
 85{
 86	struct TCP_Server_Info *server = tcon->ses->server;
 87	char *sharename;
 88	struct cifs_fscache_super_auxdata auxdata;
 89
 90	sharename = extract_sharename(tcon->treeName);
 91	if (IS_ERR(sharename)) {
 92		cifs_dbg(FYI, "%s: couldn't extract sharename\n", __func__);
 93		tcon->fscache = NULL;
 94		return;
 95	}
 96
 97	memset(&auxdata, 0, sizeof(auxdata));
 98	auxdata.resource_id = tcon->resource_id;
 99	auxdata.vol_create_time = tcon->vol_create_time;
100	auxdata.vol_serial_number = tcon->vol_serial_number;
101
102	tcon->fscache =
103		fscache_acquire_cookie(server->fscache,
104				       &cifs_fscache_super_index_def,
105				       sharename, strlen(sharename),
106				       &auxdata, sizeof(auxdata),
107				       tcon, 0, true);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
108	kfree(sharename);
109	cifs_dbg(FYI, "%s: (0x%p/0x%p)\n",
110		 __func__, server->fscache, tcon->fscache);
111}
112
113void cifs_fscache_release_super_cookie(struct cifs_tcon *tcon)
114{
115	struct cifs_fscache_super_auxdata auxdata;
116
117	memset(&auxdata, 0, sizeof(auxdata));
118	auxdata.resource_id = tcon->resource_id;
119	auxdata.vol_create_time = tcon->vol_create_time;
120	auxdata.vol_serial_number = tcon->vol_serial_number;
121
122	cifs_dbg(FYI, "%s: (0x%p)\n", __func__, tcon->fscache);
123	fscache_relinquish_cookie(tcon->fscache, &auxdata, false);
124	tcon->fscache = NULL;
125}
126
127static void cifs_fscache_acquire_inode_cookie(struct cifsInodeInfo *cifsi,
128					      struct cifs_tcon *tcon)
129{
130	struct cifs_fscache_inode_auxdata auxdata;
131
132	memset(&auxdata, 0, sizeof(auxdata));
133	auxdata.eof = cifsi->server_eof;
134	auxdata.last_write_time_sec = cifsi->vfs_inode.i_mtime.tv_sec;
135	auxdata.last_change_time_sec = cifsi->vfs_inode.i_ctime.tv_sec;
136	auxdata.last_write_time_nsec = cifsi->vfs_inode.i_mtime.tv_nsec;
137	auxdata.last_change_time_nsec = cifsi->vfs_inode.i_ctime.tv_nsec;
138
139	cifsi->fscache =
140		fscache_acquire_cookie(tcon->fscache,
141				       &cifs_fscache_inode_object_def,
142				       &cifsi->uniqueid, sizeof(cifsi->uniqueid),
143				       &auxdata, sizeof(auxdata),
144				       cifsi, cifsi->vfs_inode.i_size, true);
145}
146
147static void cifs_fscache_enable_inode_cookie(struct inode *inode)
148{
 
149	struct cifsInodeInfo *cifsi = CIFS_I(inode);
150	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
151	struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
152
153	if (cifsi->fscache)
154		return;
155
156	if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_FSCACHE))
157		return;
158
159	cifs_fscache_acquire_inode_cookie(cifsi, tcon);
160
161	cifs_dbg(FYI, "%s: got FH cookie (0x%p/0x%p)\n",
162		 __func__, tcon->fscache, cifsi->fscache);
163}
164
165void cifs_fscache_release_inode_cookie(struct inode *inode)
166{
167	struct cifs_fscache_inode_auxdata auxdata;
168	struct cifsInodeInfo *cifsi = CIFS_I(inode);
 
169
170	if (cifsi->fscache) {
171		memset(&auxdata, 0, sizeof(auxdata));
172		auxdata.eof = cifsi->server_eof;
173		auxdata.last_write_time_sec = cifsi->vfs_inode.i_mtime.tv_sec;
174		auxdata.last_change_time_sec = cifsi->vfs_inode.i_ctime.tv_sec;
175		auxdata.last_write_time_nsec = cifsi->vfs_inode.i_mtime.tv_nsec;
176		auxdata.last_change_time_nsec = cifsi->vfs_inode.i_ctime.tv_nsec;
177
178		cifs_dbg(FYI, "%s: (0x%p)\n", __func__, cifsi->fscache);
179		fscache_relinquish_cookie(cifsi->fscache, &auxdata, false);
180		cifsi->fscache = NULL;
181	}
182}
183
184static void cifs_fscache_disable_inode_cookie(struct inode *inode)
185{
186	struct cifsInodeInfo *cifsi = CIFS_I(inode);
 
187
188	if (cifsi->fscache) {
189		cifs_dbg(FYI, "%s: (0x%p)\n", __func__, cifsi->fscache);
190		fscache_uncache_all_inode_pages(cifsi->fscache, inode);
191		fscache_relinquish_cookie(cifsi->fscache, NULL, true);
192		cifsi->fscache = NULL;
193	}
194}
195
196void cifs_fscache_set_inode_cookie(struct inode *inode, struct file *filp)
 
 
 
197{
198	if ((filp->f_flags & O_ACCMODE) != O_RDONLY)
199		cifs_fscache_disable_inode_cookie(inode);
200	else
201		cifs_fscache_enable_inode_cookie(inode);
202}
203
204void cifs_fscache_reset_inode_cookie(struct inode *inode)
205{
206	struct cifsInodeInfo *cifsi = CIFS_I(inode);
207	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
208	struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
209	struct fscache_cookie *old = cifsi->fscache;
210
211	if (cifsi->fscache) {
212		/* retire the current fscache cache and get a new one */
213		fscache_relinquish_cookie(cifsi->fscache, NULL, true);
214
215		cifs_fscache_acquire_inode_cookie(cifsi, tcon);
216		cifs_dbg(FYI, "%s: new cookie 0x%p oldcookie 0x%p\n",
217			 __func__, cifsi->fscache, old);
218	}
219}
220
221int cifs_fscache_release_page(struct page *page, gfp_t gfp)
222{
223	if (PageFsCache(page)) {
224		struct inode *inode = page->mapping->host;
225		struct cifsInodeInfo *cifsi = CIFS_I(inode);
226
227		cifs_dbg(FYI, "%s: (0x%p/0x%p)\n",
228			 __func__, page, cifsi->fscache);
229		if (!fscache_maybe_release_page(cifsi->fscache, page, gfp))
230			return 0;
231	}
232
233	return 1;
234}
235
236static void cifs_readpage_from_fscache_complete(struct page *page, void *ctx,
237						int error)
238{
239	cifs_dbg(FYI, "%s: (0x%p/%d)\n", __func__, page, error);
240	if (!error)
241		SetPageUptodate(page);
242	unlock_page(page);
243}
244
245/*
246 * Retrieve a page from FS-Cache
247 */
248int __cifs_readpage_from_fscache(struct inode *inode, struct page *page)
 
249{
 
 
 
 
 
 
250	int ret;
251
252	cifs_dbg(FYI, "%s: (fsc:%p, p:%p, i:0x%p\n",
253		 __func__, CIFS_I(inode)->fscache, page, inode);
254	ret = fscache_read_or_alloc_page(CIFS_I(inode)->fscache, page,
255					 cifs_readpage_from_fscache_complete,
256					 NULL,
257					 GFP_KERNEL);
258	switch (ret) {
259
260	case 0: /* page found in fscache, read submitted */
261		cifs_dbg(FYI, "%s: submitted\n", __func__);
262		return ret;
263	case -ENOBUFS:	/* page won't be cached */
264	case -ENODATA:	/* page not in cache */
265		cifs_dbg(FYI, "%s: %d\n", __func__, ret);
266		return 1;
267
268	default:
269		cifs_dbg(VFS, "unknown error ret = %d\n", ret);
270	}
 
 
271	return ret;
272}
273
274/*
275 * Retrieve a set of pages from FS-Cache
276 */
277int __cifs_readpages_from_fscache(struct inode *inode,
278				struct address_space *mapping,
279				struct list_head *pages,
280				unsigned *nr_pages)
281{
282	int ret;
283
284	cifs_dbg(FYI, "%s: (0x%p/%u/0x%p)\n",
285		 __func__, CIFS_I(inode)->fscache, *nr_pages, inode);
286	ret = fscache_read_or_alloc_pages(CIFS_I(inode)->fscache, mapping,
287					  pages, nr_pages,
288					  cifs_readpage_from_fscache_complete,
289					  NULL,
290					  mapping_gfp_mask(mapping));
291	switch (ret) {
292	case 0:	/* read submitted to the cache for all pages */
293		cifs_dbg(FYI, "%s: submitted\n", __func__);
294		return ret;
295
296	case -ENOBUFS:	/* some pages are not cached and can't be */
297	case -ENODATA:	/* some pages are not cached */
298		cifs_dbg(FYI, "%s: no page\n", __func__);
299		return 1;
300
301	default:
302		cifs_dbg(FYI, "unknown error ret = %d\n", ret);
303	}
304
305	return ret;
306}
307
308void __cifs_readpage_to_fscache(struct inode *inode, struct page *page)
309{
310	struct cifsInodeInfo *cifsi = CIFS_I(inode);
311	int ret;
312
313	cifs_dbg(FYI, "%s: (fsc: %p, p: %p, i: %p)\n",
314		 __func__, cifsi->fscache, page, inode);
315	ret = fscache_write_page(cifsi->fscache, page,
316				 cifsi->vfs_inode.i_size, GFP_KERNEL);
317	if (ret != 0)
318		fscache_uncache_page(cifsi->fscache, page);
319}
320
321void __cifs_fscache_readpages_cancel(struct inode *inode, struct list_head *pages)
322{
323	cifs_dbg(FYI, "%s: (fsc: %p, i: %p)\n",
324		 __func__, CIFS_I(inode)->fscache, inode);
325	fscache_readpages_cancel(CIFS_I(inode)->fscache, pages);
326}
 
 
 
 
 
 
 
 
 
 
 
327
328void __cifs_fscache_invalidate_page(struct page *page, struct inode *inode)
329{
330	struct cifsInodeInfo *cifsi = CIFS_I(inode);
331	struct fscache_cookie *cookie = cifsi->fscache;
 
 
 
 
332
333	cifs_dbg(FYI, "%s: (0x%p/0x%p)\n", __func__, page, cookie);
334	fscache_wait_on_page_write(cookie, page);
335	fscache_uncache_page(cookie, page);
336}