blob: af5ed6b9c54dd868246135e8394380cd47726061 [file] [log] [blame]
Jeffle Xuc6be2bd2022-04-25 20:21:33 +08001// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (C) 2022, Alibaba Cloud
Jia Zhu8b7adf12022-09-18 12:34:53 +08004 * Copyright (C) 2022, Bytedance Inc. All rights reserved.
Jeffle Xuc6be2bd2022-04-25 20:21:33 +08005 */
6#include <linux/fscache.h>
7#include "internal.h"
8
Jia Zhu8b7adf12022-09-18 12:34:53 +08009static DEFINE_MUTEX(erofs_domain_list_lock);
Jia Zhu7d419632022-09-18 19:01:50 +080010static DEFINE_MUTEX(erofs_domain_cookies_lock);
Jia Zhu8b7adf12022-09-18 12:34:53 +080011static LIST_HEAD(erofs_domain_list);
Jia Zhua9849562022-09-18 12:34:54 +080012static struct vfsmount *erofs_pseudo_mnt;
Jia Zhu8b7adf12022-09-18 12:34:53 +080013
Xin Yind435d532022-05-09 15:40:28 +080014static struct netfs_io_request *erofs_fscache_alloc_request(struct address_space *mapping,
15 loff_t start, size_t len)
16{
17 struct netfs_io_request *rreq;
18
19 rreq = kzalloc(sizeof(struct netfs_io_request), GFP_KERNEL);
20 if (!rreq)
21 return ERR_PTR(-ENOMEM);
22
23 rreq->start = start;
24 rreq->len = len;
25 rreq->mapping = mapping;
Xin Yinb5cb79d2022-05-27 18:18:00 +080026 rreq->inode = mapping->host;
Xin Yind435d532022-05-09 15:40:28 +080027 INIT_LIST_HEAD(&rreq->subrequests);
28 refcount_set(&rreq->ref, 1);
29 return rreq;
30}
31
32static void erofs_fscache_put_request(struct netfs_io_request *rreq)
33{
34 if (!refcount_dec_and_test(&rreq->ref))
35 return;
36 if (rreq->cache_resources.ops)
37 rreq->cache_resources.ops->end_operation(&rreq->cache_resources);
38 kfree(rreq);
39}
40
41static void erofs_fscache_put_subrequest(struct netfs_io_subrequest *subreq)
42{
43 if (!refcount_dec_and_test(&subreq->ref))
44 return;
45 erofs_fscache_put_request(subreq->rreq);
46 kfree(subreq);
47}
48
49static void erofs_fscache_clear_subrequests(struct netfs_io_request *rreq)
50{
51 struct netfs_io_subrequest *subreq;
52
53 while (!list_empty(&rreq->subrequests)) {
54 subreq = list_first_entry(&rreq->subrequests,
55 struct netfs_io_subrequest, rreq_link);
56 list_del(&subreq->rreq_link);
57 erofs_fscache_put_subrequest(subreq);
58 }
59}
60
61static void erofs_fscache_rreq_unlock_folios(struct netfs_io_request *rreq)
62{
63 struct netfs_io_subrequest *subreq;
64 struct folio *folio;
65 unsigned int iopos = 0;
66 pgoff_t start_page = rreq->start / PAGE_SIZE;
67 pgoff_t last_page = ((rreq->start + rreq->len) / PAGE_SIZE) - 1;
68 bool subreq_failed = false;
69
70 XA_STATE(xas, &rreq->mapping->i_pages, start_page);
71
72 subreq = list_first_entry(&rreq->subrequests,
73 struct netfs_io_subrequest, rreq_link);
74 subreq_failed = (subreq->error < 0);
75
76 rcu_read_lock();
77 xas_for_each(&xas, folio, last_page) {
Jingbo Xu37020bb2022-11-14 20:19:43 +080078 unsigned int pgpos, pgend;
Xin Yind435d532022-05-09 15:40:28 +080079 bool pg_failed = false;
80
Jingbo Xu37020bb2022-11-14 20:19:43 +080081 if (xas_retry(&xas, folio))
82 continue;
83
84 pgpos = (folio_index(folio) - start_page) * PAGE_SIZE;
85 pgend = pgpos + folio_size(folio);
86
Xin Yind435d532022-05-09 15:40:28 +080087 for (;;) {
88 if (!subreq) {
89 pg_failed = true;
90 break;
91 }
92
93 pg_failed |= subreq_failed;
94 if (pgend < iopos + subreq->len)
95 break;
96
97 iopos += subreq->len;
98 if (!list_is_last(&subreq->rreq_link,
99 &rreq->subrequests)) {
100 subreq = list_next_entry(subreq, rreq_link);
101 subreq_failed = (subreq->error < 0);
102 } else {
103 subreq = NULL;
104 subreq_failed = false;
105 }
106 if (pgend == iopos)
107 break;
108 }
109
110 if (!pg_failed)
111 folio_mark_uptodate(folio);
112
113 folio_unlock(folio);
114 }
115 rcu_read_unlock();
116}
117
118static void erofs_fscache_rreq_complete(struct netfs_io_request *rreq)
119{
120 erofs_fscache_rreq_unlock_folios(rreq);
121 erofs_fscache_clear_subrequests(rreq);
122 erofs_fscache_put_request(rreq);
123}
124
125static void erofc_fscache_subreq_complete(void *priv,
126 ssize_t transferred_or_error, bool was_async)
127{
128 struct netfs_io_subrequest *subreq = priv;
129 struct netfs_io_request *rreq = subreq->rreq;
130
131 if (IS_ERR_VALUE(transferred_or_error))
132 subreq->error = transferred_or_error;
133
134 if (atomic_dec_and_test(&rreq->nr_outstanding))
135 erofs_fscache_rreq_complete(rreq);
136
137 erofs_fscache_put_subrequest(subreq);
138}
139
Jeffle Xuec00b5e2022-04-25 20:21:36 +0800140/*
141 * Read data from fscache and fill the read data into page cache described by
Xin Yind435d532022-05-09 15:40:28 +0800142 * @rreq, which shall be both aligned with PAGE_SIZE. @pstart describes
Jeffle Xuec00b5e2022-04-25 20:21:36 +0800143 * the start physical address in the cache file.
144 */
Xin Yind435d532022-05-09 15:40:28 +0800145static int erofs_fscache_read_folios_async(struct fscache_cookie *cookie,
146 struct netfs_io_request *rreq, loff_t pstart)
Jeffle Xuec00b5e2022-04-25 20:21:36 +0800147{
148 enum netfs_io_source source;
Xin Yind435d532022-05-09 15:40:28 +0800149 struct super_block *sb = rreq->mapping->host->i_sb;
150 struct netfs_io_subrequest *subreq;
151 struct netfs_cache_resources *cres = &rreq->cache_resources;
Jeffle Xuec00b5e2022-04-25 20:21:36 +0800152 struct iov_iter iter;
Xin Yind435d532022-05-09 15:40:28 +0800153 loff_t start = rreq->start;
154 size_t len = rreq->len;
Jeffle Xuec00b5e2022-04-25 20:21:36 +0800155 size_t done = 0;
156 int ret;
157
Xin Yind435d532022-05-09 15:40:28 +0800158 atomic_set(&rreq->nr_outstanding, 1);
159
Jeffle Xuec00b5e2022-04-25 20:21:36 +0800160 ret = fscache_begin_read_operation(cres, cookie);
161 if (ret)
Xin Yind435d532022-05-09 15:40:28 +0800162 goto out;
Jeffle Xuec00b5e2022-04-25 20:21:36 +0800163
164 while (done < len) {
Xin Yind435d532022-05-09 15:40:28 +0800165 subreq = kzalloc(sizeof(struct netfs_io_subrequest),
166 GFP_KERNEL);
167 if (subreq) {
168 INIT_LIST_HEAD(&subreq->rreq_link);
169 refcount_set(&subreq->ref, 2);
170 subreq->rreq = rreq;
171 refcount_inc(&rreq->ref);
172 } else {
173 ret = -ENOMEM;
174 goto out;
175 }
Jeffle Xuec00b5e2022-04-25 20:21:36 +0800176
Xin Yind435d532022-05-09 15:40:28 +0800177 subreq->start = pstart + done;
178 subreq->len = len - done;
179 subreq->flags = 1 << NETFS_SREQ_ONDEMAND;
180
181 list_add_tail(&subreq->rreq_link, &rreq->subrequests);
182
183 source = cres->ops->prepare_read(subreq, LLONG_MAX);
184 if (WARN_ON(subreq->len == 0))
Jeffle Xuec00b5e2022-04-25 20:21:36 +0800185 source = NETFS_INVALID_READ;
186 if (source != NETFS_READ_FROM_CACHE) {
187 erofs_err(sb, "failed to fscache prepare_read (source %d)",
188 source);
189 ret = -EIO;
Xin Yind435d532022-05-09 15:40:28 +0800190 subreq->error = ret;
191 erofs_fscache_put_subrequest(subreq);
Jeffle Xuec00b5e2022-04-25 20:21:36 +0800192 goto out;
193 }
194
Xin Yind435d532022-05-09 15:40:28 +0800195 atomic_inc(&rreq->nr_outstanding);
196
197 iov_iter_xarray(&iter, READ, &rreq->mapping->i_pages,
198 start + done, subreq->len);
199
200 ret = fscache_read(cres, subreq->start, &iter,
201 NETFS_READ_HOLE_FAIL,
202 erofc_fscache_subreq_complete, subreq);
203 if (ret == -EIOCBQUEUED)
204 ret = 0;
Jeffle Xuec00b5e2022-04-25 20:21:36 +0800205 if (ret) {
206 erofs_err(sb, "failed to fscache_read (ret %d)", ret);
207 goto out;
208 }
209
Xin Yind435d532022-05-09 15:40:28 +0800210 done += subreq->len;
Jeffle Xuec00b5e2022-04-25 20:21:36 +0800211 }
212out:
Xin Yind435d532022-05-09 15:40:28 +0800213 if (atomic_dec_and_test(&rreq->nr_outstanding))
214 erofs_fscache_rreq_complete(rreq);
215
Jeffle Xuec00b5e2022-04-25 20:21:36 +0800216 return ret;
217}
218
Linus Torvaldsfdaf9a52022-05-24 19:55:07 -0700219static int erofs_fscache_meta_read_folio(struct file *data, struct folio *folio)
Jeffle Xu5375e7c2022-04-25 20:21:39 +0800220{
221 int ret;
Jeffle Xu5375e7c2022-04-25 20:21:39 +0800222 struct super_block *sb = folio_mapping(folio)->host->i_sb;
Xin Yind435d532022-05-09 15:40:28 +0800223 struct netfs_io_request *rreq;
Jeffle Xu5375e7c2022-04-25 20:21:39 +0800224 struct erofs_map_dev mdev = {
225 .m_deviceid = 0,
226 .m_pa = folio_pos(folio),
227 };
228
229 ret = erofs_map_dev(sb, &mdev);
230 if (ret)
231 goto out;
232
Xin Yind435d532022-05-09 15:40:28 +0800233 rreq = erofs_fscache_alloc_request(folio_mapping(folio),
234 folio_pos(folio), folio_size(folio));
Sun Ke5bd96282022-08-15 11:48:29 +0800235 if (IS_ERR(rreq)) {
236 ret = PTR_ERR(rreq);
Xin Yind435d532022-05-09 15:40:28 +0800237 goto out;
Sun Ke5bd96282022-08-15 11:48:29 +0800238 }
Xin Yind435d532022-05-09 15:40:28 +0800239
240 return erofs_fscache_read_folios_async(mdev.m_fscache->cookie,
241 rreq, mdev.m_pa);
Jeffle Xu5375e7c2022-04-25 20:21:39 +0800242out:
243 folio_unlock(folio);
244 return ret;
245}
246
Jingbo Xu1ae94702022-09-22 14:24:14 +0800247/*
248 * Read into page cache in the range described by (@pos, @len).
249 *
250 * On return, the caller is responsible for page unlocking if the output @unlock
251 * is true, or the callee will take this responsibility through netfs_io_request
252 * interface.
253 *
254 * The return value is the number of bytes successfully handled, or negative
255 * error code on failure. The only exception is that, the length of the range
256 * instead of the error code is returned on failure after netfs_io_request is
257 * allocated, so that .readahead() could advance rac accordingly.
258 */
259static int erofs_fscache_data_read(struct address_space *mapping,
260 loff_t pos, size_t len, bool *unlock)
Jeffle Xubd735bd2022-04-25 20:21:41 +0800261{
Jingbo Xu1ae94702022-09-22 14:24:14 +0800262 struct inode *inode = mapping->host;
Jeffle Xu1442b022022-04-25 20:21:40 +0800263 struct super_block *sb = inode->i_sb;
Jingbo Xu1ae94702022-09-22 14:24:14 +0800264 struct netfs_io_request *rreq;
Jeffle Xu1442b022022-04-25 20:21:40 +0800265 struct erofs_map_blocks map;
266 struct erofs_map_dev mdev;
Jingbo Xu1ae94702022-09-22 14:24:14 +0800267 struct iov_iter iter;
268 size_t count;
Jeffle Xu1442b022022-04-25 20:21:40 +0800269 int ret;
270
Jingbo Xu1ae94702022-09-22 14:24:14 +0800271 *unlock = true;
Jeffle Xu1442b022022-04-25 20:21:40 +0800272
Jeffle Xu1442b022022-04-25 20:21:40 +0800273 map.m_la = pos;
Jeffle Xu1442b022022-04-25 20:21:40 +0800274 ret = erofs_map_blocks(inode, &map, EROFS_GET_BLOCKS_RAW);
275 if (ret)
Jingbo Xu1ae94702022-09-22 14:24:14 +0800276 return ret;
Jeffle Xu1442b022022-04-25 20:21:40 +0800277
Jeffle Xubd735bd2022-04-25 20:21:41 +0800278 if (map.m_flags & EROFS_MAP_META) {
Jingbo Xu1ae94702022-09-22 14:24:14 +0800279 struct erofs_buf buf = __EROFS_BUF_INITIALIZER;
280 erofs_blk_t blknr;
281 size_t offset, size;
282 void *src;
283
284 /* For tail packing layout, the offset may be non-zero. */
285 offset = erofs_blkoff(map.m_pa);
286 blknr = erofs_blknr(map.m_pa);
287 size = map.m_llen;
288
289 src = erofs_read_metabuf(&buf, sb, blknr, EROFS_KMAP);
290 if (IS_ERR(src))
291 return PTR_ERR(src);
292
293 iov_iter_xarray(&iter, READ, &mapping->i_pages, pos, PAGE_SIZE);
Jingbo Xu75e43352022-11-04 13:40:27 +0800294 if (copy_to_iter(src + offset, size, &iter) != size) {
295 erofs_put_metabuf(&buf);
Jingbo Xu1ae94702022-09-22 14:24:14 +0800296 return -EFAULT;
Jingbo Xu75e43352022-11-04 13:40:27 +0800297 }
Jingbo Xu1ae94702022-09-22 14:24:14 +0800298 iov_iter_zero(PAGE_SIZE - size, &iter);
299 erofs_put_metabuf(&buf);
300 return PAGE_SIZE;
301 }
302
Jingbo Xu1ae94702022-09-22 14:24:14 +0800303 if (!(map.m_flags & EROFS_MAP_MAPPED)) {
Jingbo Xue6d9f9b2022-11-04 13:40:28 +0800304 count = len;
Jingbo Xu1ae94702022-09-22 14:24:14 +0800305 iov_iter_xarray(&iter, READ, &mapping->i_pages, pos, count);
306 iov_iter_zero(count, &iter);
307 return count;
Jeffle Xubd735bd2022-04-25 20:21:41 +0800308 }
309
Jingbo Xue6d9f9b2022-11-04 13:40:28 +0800310 count = min_t(size_t, map.m_llen - (pos - map.m_la), len);
311 DBG_BUGON(!count || count % PAGE_SIZE);
312
Jeffle Xu1442b022022-04-25 20:21:40 +0800313 mdev = (struct erofs_map_dev) {
314 .m_deviceid = map.m_deviceid,
315 .m_pa = map.m_pa,
316 };
Jeffle Xu1442b022022-04-25 20:21:40 +0800317 ret = erofs_map_dev(sb, &mdev);
318 if (ret)
Jingbo Xu1ae94702022-09-22 14:24:14 +0800319 return ret;
Jeffle Xu1442b022022-04-25 20:21:40 +0800320
Jingbo Xu1ae94702022-09-22 14:24:14 +0800321 rreq = erofs_fscache_alloc_request(mapping, pos, count);
322 if (IS_ERR(rreq))
323 return PTR_ERR(rreq);
Xin Yind435d532022-05-09 15:40:28 +0800324
Jingbo Xu1ae94702022-09-22 14:24:14 +0800325 *unlock = false;
326 erofs_fscache_read_folios_async(mdev.m_fscache->cookie,
327 rreq, mdev.m_pa + (pos - map.m_la));
328 return count;
Jeffle Xu1442b022022-04-25 20:21:40 +0800329}
330
Jingbo Xu1ae94702022-09-22 14:24:14 +0800331static int erofs_fscache_read_folio(struct file *file, struct folio *folio)
Jeffle Xuc665b392022-04-25 20:21:42 +0800332{
Jingbo Xu1ae94702022-09-22 14:24:14 +0800333 bool unlock;
334 int ret;
335
336 DBG_BUGON(folio_size(folio) != EROFS_BLKSIZ);
337
338 ret = erofs_fscache_data_read(folio_mapping(folio), folio_pos(folio),
339 folio_size(folio), &unlock);
340 if (unlock) {
341 if (ret > 0)
Xin Yind435d532022-05-09 15:40:28 +0800342 folio_mark_uptodate(folio);
Jingbo Xu1ae94702022-09-22 14:24:14 +0800343 folio_unlock(folio);
Jeffle Xuc665b392022-04-25 20:21:42 +0800344 }
Jingbo Xu1ae94702022-09-22 14:24:14 +0800345 return ret < 0 ? ret : 0;
Jeffle Xuc665b392022-04-25 20:21:42 +0800346}
347
348static void erofs_fscache_readahead(struct readahead_control *rac)
349{
Jingbo Xu1ae94702022-09-22 14:24:14 +0800350 struct folio *folio;
351 size_t len, done = 0;
352 loff_t start, pos;
353 bool unlock;
354 int ret, size;
Jeffle Xuc665b392022-04-25 20:21:42 +0800355
356 if (!readahead_count(rac))
357 return;
358
359 start = readahead_pos(rac);
360 len = readahead_length(rac);
361
362 do {
Jeffle Xuc665b392022-04-25 20:21:42 +0800363 pos = start + done;
Jingbo Xu1ae94702022-09-22 14:24:14 +0800364 ret = erofs_fscache_data_read(rac->mapping, pos,
365 len - done, &unlock);
366 if (ret <= 0)
Jeffle Xuc665b392022-04-25 20:21:42 +0800367 return;
368
Jingbo Xu1ae94702022-09-22 14:24:14 +0800369 size = ret;
370 while (size) {
371 folio = readahead_folio(rac);
372 size -= folio_size(folio);
373 if (unlock) {
Jeffle Xuc665b392022-04-25 20:21:42 +0800374 folio_mark_uptodate(folio);
Jingbo Xu1ae94702022-09-22 14:24:14 +0800375 folio_unlock(folio);
Jeffle Xuc665b392022-04-25 20:21:42 +0800376 }
Jeffle Xuc665b392022-04-25 20:21:42 +0800377 }
Jingbo Xu1ae94702022-09-22 14:24:14 +0800378 } while ((done += ret) < len);
Jeffle Xuc665b392022-04-25 20:21:42 +0800379}
380
Jeffle Xu3c265d72022-04-25 20:21:35 +0800381static const struct address_space_operations erofs_fscache_meta_aops = {
Linus Torvaldsfdaf9a52022-05-24 19:55:07 -0700382 .read_folio = erofs_fscache_meta_read_folio,
Jeffle Xu3c265d72022-04-25 20:21:35 +0800383};
384
Jeffle Xu1442b022022-04-25 20:21:40 +0800385const struct address_space_operations erofs_fscache_access_aops = {
Linus Torvaldsfdaf9a52022-05-24 19:55:07 -0700386 .read_folio = erofs_fscache_read_folio,
Jeffle Xuc665b392022-04-25 20:21:42 +0800387 .readahead = erofs_fscache_readahead,
Jeffle Xu1442b022022-04-25 20:21:40 +0800388};
389
Jia Zhu8b7adf12022-09-18 12:34:53 +0800390static void erofs_fscache_domain_put(struct erofs_domain *domain)
391{
392 if (!domain)
393 return;
394 mutex_lock(&erofs_domain_list_lock);
395 if (refcount_dec_and_test(&domain->ref)) {
396 list_del(&domain->list);
Jia Zhua9849562022-09-18 12:34:54 +0800397 if (list_empty(&erofs_domain_list)) {
398 kern_unmount(erofs_pseudo_mnt);
399 erofs_pseudo_mnt = NULL;
400 }
Jia Zhu8b7adf12022-09-18 12:34:53 +0800401 mutex_unlock(&erofs_domain_list_lock);
402 fscache_relinquish_volume(domain->volume, NULL, false);
403 kfree(domain->domain_id);
404 kfree(domain);
405 return;
406 }
407 mutex_unlock(&erofs_domain_list_lock);
408}
409
410static int erofs_fscache_register_volume(struct super_block *sb)
411{
412 struct erofs_sb_info *sbi = EROFS_SB(sb);
Jingbo Xu39bfcb82022-10-21 10:31:53 +0800413 char *domain_id = sbi->domain_id;
Jia Zhu8b7adf12022-09-18 12:34:53 +0800414 struct fscache_volume *volume;
415 char *name;
416 int ret = 0;
417
418 name = kasprintf(GFP_KERNEL, "erofs,%s",
Jingbo Xu39bfcb82022-10-21 10:31:53 +0800419 domain_id ? domain_id : sbi->fsid);
Jia Zhu8b7adf12022-09-18 12:34:53 +0800420 if (!name)
421 return -ENOMEM;
422
423 volume = fscache_acquire_volume(name, NULL, NULL, 0);
424 if (IS_ERR_OR_NULL(volume)) {
425 erofs_err(sb, "failed to register volume for %s", name);
426 ret = volume ? PTR_ERR(volume) : -EOPNOTSUPP;
427 volume = NULL;
428 }
429
430 sbi->volume = volume;
431 kfree(name);
432 return ret;
433}
434
435static int erofs_fscache_init_domain(struct super_block *sb)
436{
437 int err;
438 struct erofs_domain *domain;
439 struct erofs_sb_info *sbi = EROFS_SB(sb);
440
441 domain = kzalloc(sizeof(struct erofs_domain), GFP_KERNEL);
442 if (!domain)
443 return -ENOMEM;
444
Jingbo Xu39bfcb82022-10-21 10:31:53 +0800445 domain->domain_id = kstrdup(sbi->domain_id, GFP_KERNEL);
Jia Zhu8b7adf12022-09-18 12:34:53 +0800446 if (!domain->domain_id) {
447 kfree(domain);
448 return -ENOMEM;
449 }
450
451 err = erofs_fscache_register_volume(sb);
452 if (err)
453 goto out;
454
Jia Zhua9849562022-09-18 12:34:54 +0800455 if (!erofs_pseudo_mnt) {
456 erofs_pseudo_mnt = kern_mount(&erofs_fs_type);
457 if (IS_ERR(erofs_pseudo_mnt)) {
458 err = PTR_ERR(erofs_pseudo_mnt);
459 goto out;
460 }
461 }
462
Jia Zhu8b7adf12022-09-18 12:34:53 +0800463 domain->volume = sbi->volume;
464 refcount_set(&domain->ref, 1);
465 list_add(&domain->list, &erofs_domain_list);
466 sbi->domain = domain;
467 return 0;
468out:
469 kfree(domain->domain_id);
470 kfree(domain);
471 return err;
472}
473
474static int erofs_fscache_register_domain(struct super_block *sb)
475{
476 int err;
477 struct erofs_domain *domain;
478 struct erofs_sb_info *sbi = EROFS_SB(sb);
479
480 mutex_lock(&erofs_domain_list_lock);
481 list_for_each_entry(domain, &erofs_domain_list, list) {
Jingbo Xu39bfcb82022-10-21 10:31:53 +0800482 if (!strcmp(domain->domain_id, sbi->domain_id)) {
Jia Zhu8b7adf12022-09-18 12:34:53 +0800483 sbi->domain = domain;
484 sbi->volume = domain->volume;
485 refcount_inc(&domain->ref);
486 mutex_unlock(&erofs_domain_list_lock);
487 return 0;
488 }
489 }
490 err = erofs_fscache_init_domain(sb);
491 mutex_unlock(&erofs_domain_list_lock);
492 return err;
493}
494
Jia Zhu7d419632022-09-18 19:01:50 +0800495static
496struct erofs_fscache *erofs_fscache_acquire_cookie(struct super_block *sb,
497 char *name, bool need_inode)
Jeffle Xub02c6022022-04-25 20:21:34 +0800498{
499 struct fscache_volume *volume = EROFS_SB(sb)->volume;
500 struct erofs_fscache *ctx;
501 struct fscache_cookie *cookie;
Jeffle Xu3c265d72022-04-25 20:21:35 +0800502 int ret;
Jeffle Xub02c6022022-04-25 20:21:34 +0800503
504 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
505 if (!ctx)
Jia Zhue1de2da2022-09-18 12:34:52 +0800506 return ERR_PTR(-ENOMEM);
Jeffle Xub02c6022022-04-25 20:21:34 +0800507
508 cookie = fscache_acquire_cookie(volume, FSCACHE_ADV_WANT_CACHE_SIZE,
509 name, strlen(name), NULL, 0, 0);
510 if (!cookie) {
511 erofs_err(sb, "failed to get cookie for %s", name);
Jeffle Xu3c265d72022-04-25 20:21:35 +0800512 ret = -EINVAL;
513 goto err;
Jeffle Xub02c6022022-04-25 20:21:34 +0800514 }
515
516 fscache_use_cookie(cookie, false);
517 ctx->cookie = cookie;
518
Jeffle Xu3c265d72022-04-25 20:21:35 +0800519 if (need_inode) {
520 struct inode *const inode = new_inode(sb);
521
522 if (!inode) {
523 erofs_err(sb, "failed to get anon inode for %s", name);
524 ret = -ENOMEM;
525 goto err_cookie;
526 }
527
528 set_nlink(inode, 1);
529 inode->i_size = OFFSET_MAX;
530 inode->i_mapping->a_ops = &erofs_fscache_meta_aops;
531 mapping_set_gfp_mask(inode->i_mapping, GFP_NOFS);
532
533 ctx->inode = inode;
534 }
535
Jia Zhue1de2da2022-09-18 12:34:52 +0800536 return ctx;
Jeffle Xu3c265d72022-04-25 20:21:35 +0800537
538err_cookie:
539 fscache_unuse_cookie(ctx->cookie, NULL, NULL);
540 fscache_relinquish_cookie(ctx->cookie, false);
Jeffle Xu3c265d72022-04-25 20:21:35 +0800541err:
542 kfree(ctx);
Jia Zhue1de2da2022-09-18 12:34:52 +0800543 return ERR_PTR(ret);
Jeffle Xub02c6022022-04-25 20:21:34 +0800544}
545
Jia Zhu7d419632022-09-18 19:01:50 +0800546static void erofs_fscache_relinquish_cookie(struct erofs_fscache *ctx)
Jeffle Xub02c6022022-04-25 20:21:34 +0800547{
Jeffle Xub02c6022022-04-25 20:21:34 +0800548 fscache_unuse_cookie(ctx->cookie, NULL, NULL);
549 fscache_relinquish_cookie(ctx->cookie, false);
Jeffle Xu3c265d72022-04-25 20:21:35 +0800550 iput(ctx->inode);
Jia Zhu7d419632022-09-18 19:01:50 +0800551 kfree(ctx->name);
Jeffle Xub02c6022022-04-25 20:21:34 +0800552 kfree(ctx);
Jeffle Xub02c6022022-04-25 20:21:34 +0800553}
554
Jia Zhu7d419632022-09-18 19:01:50 +0800555static
556struct erofs_fscache *erofs_fscache_domain_init_cookie(struct super_block *sb,
557 char *name, bool need_inode)
558{
559 int err;
560 struct inode *inode;
561 struct erofs_fscache *ctx;
562 struct erofs_domain *domain = EROFS_SB(sb)->domain;
563
564 ctx = erofs_fscache_acquire_cookie(sb, name, need_inode);
565 if (IS_ERR(ctx))
566 return ctx;
567
568 ctx->name = kstrdup(name, GFP_KERNEL);
569 if (!ctx->name) {
570 err = -ENOMEM;
571 goto out;
572 }
573
574 inode = new_inode(erofs_pseudo_mnt->mnt_sb);
575 if (!inode) {
576 err = -ENOMEM;
577 goto out;
578 }
579
580 ctx->domain = domain;
581 ctx->anon_inode = inode;
582 inode->i_private = ctx;
583 refcount_inc(&domain->ref);
584 return ctx;
585out:
586 erofs_fscache_relinquish_cookie(ctx);
587 return ERR_PTR(err);
588}
589
590static
591struct erofs_fscache *erofs_domain_register_cookie(struct super_block *sb,
592 char *name, bool need_inode)
593{
594 struct inode *inode;
595 struct erofs_fscache *ctx;
596 struct erofs_domain *domain = EROFS_SB(sb)->domain;
597 struct super_block *psb = erofs_pseudo_mnt->mnt_sb;
598
599 mutex_lock(&erofs_domain_cookies_lock);
Dawei Lice4b8152022-10-17 09:55:53 +0800600 spin_lock(&psb->s_inode_list_lock);
Jia Zhu7d419632022-09-18 19:01:50 +0800601 list_for_each_entry(inode, &psb->s_inodes, i_sb_list) {
602 ctx = inode->i_private;
603 if (!ctx || ctx->domain != domain || strcmp(ctx->name, name))
604 continue;
605 igrab(inode);
Dawei Lice4b8152022-10-17 09:55:53 +0800606 spin_unlock(&psb->s_inode_list_lock);
Jia Zhu7d419632022-09-18 19:01:50 +0800607 mutex_unlock(&erofs_domain_cookies_lock);
608 return ctx;
609 }
Dawei Lice4b8152022-10-17 09:55:53 +0800610 spin_unlock(&psb->s_inode_list_lock);
Jia Zhu7d419632022-09-18 19:01:50 +0800611 ctx = erofs_fscache_domain_init_cookie(sb, name, need_inode);
612 mutex_unlock(&erofs_domain_cookies_lock);
613 return ctx;
614}
615
616struct erofs_fscache *erofs_fscache_register_cookie(struct super_block *sb,
617 char *name, bool need_inode)
618{
Jingbo Xu39bfcb82022-10-21 10:31:53 +0800619 if (EROFS_SB(sb)->domain_id)
Jia Zhu7d419632022-09-18 19:01:50 +0800620 return erofs_domain_register_cookie(sb, name, need_inode);
621 return erofs_fscache_acquire_cookie(sb, name, need_inode);
622}
623
624void erofs_fscache_unregister_cookie(struct erofs_fscache *ctx)
625{
626 bool drop;
627 struct erofs_domain *domain;
628
629 if (!ctx)
630 return;
631 domain = ctx->domain;
632 if (domain) {
633 mutex_lock(&erofs_domain_cookies_lock);
634 drop = atomic_read(&ctx->anon_inode->i_count) == 1;
635 iput(ctx->anon_inode);
636 mutex_unlock(&erofs_domain_cookies_lock);
637 if (!drop)
638 return;
639 }
640
641 erofs_fscache_relinquish_cookie(ctx);
642 erofs_fscache_domain_put(domain);
643}
644
Jeffle Xuc6be2bd2022-04-25 20:21:33 +0800645int erofs_fscache_register_fs(struct super_block *sb)
646{
Jia Zhu8b7adf12022-09-18 12:34:53 +0800647 int ret;
Jeffle Xuc6be2bd2022-04-25 20:21:33 +0800648 struct erofs_sb_info *sbi = EROFS_SB(sb);
Jia Zhue1de2da2022-09-18 12:34:52 +0800649 struct erofs_fscache *fscache;
Jeffle Xuc6be2bd2022-04-25 20:21:33 +0800650
Jingbo Xu39bfcb82022-10-21 10:31:53 +0800651 if (sbi->domain_id)
Jia Zhu8b7adf12022-09-18 12:34:53 +0800652 ret = erofs_fscache_register_domain(sb);
653 else
654 ret = erofs_fscache_register_volume(sb);
655 if (ret)
656 return ret;
Jeffle Xuc6be2bd2022-04-25 20:21:33 +0800657
Jia Zhu8b7adf12022-09-18 12:34:53 +0800658 /* acquired domain/volume will be relinquished in kill_sb() on error */
Jingbo Xu39bfcb82022-10-21 10:31:53 +0800659 fscache = erofs_fscache_register_cookie(sb, sbi->fsid, true);
Jia Zhue1de2da2022-09-18 12:34:52 +0800660 if (IS_ERR(fscache))
661 return PTR_ERR(fscache);
662
663 sbi->s_fscache = fscache;
664 return 0;
Jeffle Xuc6be2bd2022-04-25 20:21:33 +0800665}
666
667void erofs_fscache_unregister_fs(struct super_block *sb)
668{
669 struct erofs_sb_info *sbi = EROFS_SB(sb);
670
Jia Zhue1de2da2022-09-18 12:34:52 +0800671 erofs_fscache_unregister_cookie(sbi->s_fscache);
Jia Zhu8b7adf12022-09-18 12:34:53 +0800672
673 if (sbi->domain)
674 erofs_fscache_domain_put(sbi->domain);
675 else
676 fscache_relinquish_volume(sbi->volume, NULL, false);
677
Jia Zhue1de2da2022-09-18 12:34:52 +0800678 sbi->s_fscache = NULL;
Jeffle Xuc6be2bd2022-04-25 20:21:33 +0800679 sbi->volume = NULL;
Jia Zhu8b7adf12022-09-18 12:34:53 +0800680 sbi->domain = NULL;
Jeffle Xuc6be2bd2022-04-25 20:21:33 +0800681}