xref: /kernel/linux/linux-6.6/fs/smb/client/fscache.c (revision 62306a36)
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 PTR_ERR(sharename);
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	if (cifsi->netfs.cache)
112		mapping_set_release_always(inode->i_mapping);
113}
114
115void cifs_fscache_unuse_inode_cookie(struct inode *inode, bool update)
116{
117	if (update) {
118		struct cifs_fscache_inode_coherency_data cd;
119		loff_t i_size = i_size_read(inode);
120
121		cifs_fscache_fill_coherency(inode, &cd);
122		fscache_unuse_cookie(cifs_inode_cookie(inode), &cd, &i_size);
123	} else {
124		fscache_unuse_cookie(cifs_inode_cookie(inode), NULL, NULL);
125	}
126}
127
128void cifs_fscache_release_inode_cookie(struct inode *inode)
129{
130	struct cifsInodeInfo *cifsi = CIFS_I(inode);
131	struct fscache_cookie *cookie = cifs_inode_cookie(inode);
132
133	if (cookie) {
134		cifs_dbg(FYI, "%s: (0x%p)\n", __func__, cookie);
135		fscache_relinquish_cookie(cookie, false);
136		cifsi->netfs.cache = NULL;
137	}
138}
139
140/*
141 * Fallback page reading interface.
142 */
143static int fscache_fallback_read_page(struct inode *inode, struct page *page)
144{
145	struct netfs_cache_resources cres;
146	struct fscache_cookie *cookie = cifs_inode_cookie(inode);
147	struct iov_iter iter;
148	struct bio_vec bvec;
149	int ret;
150
151	memset(&cres, 0, sizeof(cres));
152	bvec_set_page(&bvec, page, PAGE_SIZE, 0);
153	iov_iter_bvec(&iter, ITER_DEST, &bvec, 1, 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_pages(struct inode *inode, loff_t start, size_t len,
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	int ret;
175
176	memset(&cres, 0, sizeof(cres));
177	iov_iter_xarray(&iter, ITER_SOURCE, &inode->i_mapping->i_pages, start, len);
178
179	ret = fscache_begin_write_operation(&cres, cookie);
180	if (ret < 0)
181		return ret;
182
183	ret = cres.ops->prepare_write(&cres, &start, &len, i_size_read(inode),
184				      no_space_allocated_yet);
185	if (ret == 0)
186		ret = fscache_write(&cres, start, &iter, NULL, NULL);
187	fscache_end_operation(&cres);
188	return ret;
189}
190
191/*
192 * Retrieve a page from FS-Cache
193 */
194int __cifs_readpage_from_fscache(struct inode *inode, struct page *page)
195{
196	int ret;
197
198	cifs_dbg(FYI, "%s: (fsc:%p, p:%p, i:0x%p\n",
199		 __func__, cifs_inode_cookie(inode), page, inode);
200
201	ret = fscache_fallback_read_page(inode, page);
202	if (ret < 0)
203		return ret;
204
205	/* Read completed synchronously */
206	SetPageUptodate(page);
207	return 0;
208}
209
210void __cifs_readahead_to_fscache(struct inode *inode, loff_t pos, size_t len)
211{
212	cifs_dbg(FYI, "%s: (fsc: %p, p: %llx, l: %zx, i: %p)\n",
213		 __func__, cifs_inode_cookie(inode), pos, len, inode);
214
215	fscache_fallback_write_pages(inode, pos, len, true);
216}
217
218/*
219 * Query the cache occupancy.
220 */
221int __cifs_fscache_query_occupancy(struct inode *inode,
222				   pgoff_t first, unsigned int nr_pages,
223				   pgoff_t *_data_first,
224				   unsigned int *_data_nr_pages)
225{
226	struct netfs_cache_resources cres;
227	struct fscache_cookie *cookie = cifs_inode_cookie(inode);
228	loff_t start, data_start;
229	size_t len, data_len;
230	int ret;
231
232	ret = fscache_begin_read_operation(&cres, cookie);
233	if (ret < 0)
234		return ret;
235
236	start = first * PAGE_SIZE;
237	len = nr_pages * PAGE_SIZE;
238	ret = cres.ops->query_occupancy(&cres, start, len, PAGE_SIZE,
239					&data_start, &data_len);
240	if (ret == 0) {
241		*_data_first = data_start / PAGE_SIZE;
242		*_data_nr_pages = len / PAGE_SIZE;
243	}
244
245	fscache_end_operation(&cres);
246	return ret;
247}
248