blob: 36e569a791726cc2a80ffbcd6096e5bb93a202c1 [file] [log] [blame]
Gao Xiang29b24f62019-07-31 23:57:31 +08001// SPDX-License-Identifier: GPL-2.0-only
Gao Xiangba2b77a2018-07-26 20:21:46 +08002/*
Gao Xiangba2b77a2018-07-26 20:21:46 +08003 * Copyright (C) 2017-2018 HUAWEI, Inc.
4 * http://www.huawei.com/
5 * Created by Gao Xiang <gaoxiang25@huawei.com>
Gao Xiangba2b77a2018-07-26 20:21:46 +08006 */
7#include <linux/module.h>
8#include <linux/buffer_head.h>
9#include <linux/statfs.h>
10#include <linux/parser.h>
Gao Xiangb17500a2018-07-26 20:21:52 +080011#include <linux/seq_file.h>
Gao Xiang6af7b482019-01-14 19:40:25 +080012#include "xattr.h"
Gao Xiangba2b77a2018-07-26 20:21:46 +080013
Chao Yu13f06f42018-07-26 20:21:55 +080014#define CREATE_TRACE_POINTS
15#include <trace/events/erofs.h>
16
Gao Xiangba2b77a2018-07-26 20:21:46 +080017static struct kmem_cache *erofs_inode_cachep __read_mostly;
18
Gao Xiang99634bf2019-09-04 10:09:05 +080019static void erofs_inode_init_once(void *ptr)
Gao Xiangba2b77a2018-07-26 20:21:46 +080020{
Gao Xianga5876e22019-09-04 10:08:56 +080021 struct erofs_inode *vi = ptr;
Gao Xiangba2b77a2018-07-26 20:21:46 +080022
23 inode_init_once(&vi->vfs_inode);
24}
25
Gao Xiang99634bf2019-09-04 10:09:05 +080026static struct inode *erofs_alloc_inode(struct super_block *sb)
Gao Xiangba2b77a2018-07-26 20:21:46 +080027{
Gao Xianga5876e22019-09-04 10:08:56 +080028 struct erofs_inode *vi =
Gao Xiangba2b77a2018-07-26 20:21:46 +080029 kmem_cache_alloc(erofs_inode_cachep, GFP_KERNEL);
30
Vatsala Narange2ff9f12019-03-21 05:36:13 +053031 if (!vi)
Gao Xiangba2b77a2018-07-26 20:21:46 +080032 return NULL;
33
34 /* zero out everything except vfs_inode */
Gao Xianga5876e22019-09-04 10:08:56 +080035 memset(vi, 0, offsetof(struct erofs_inode, vfs_inode));
Gao Xiangba2b77a2018-07-26 20:21:46 +080036 return &vi->vfs_inode;
37}
38
Gao Xiang99634bf2019-09-04 10:09:05 +080039static void erofs_free_inode(struct inode *inode)
Gao Xiangba2b77a2018-07-26 20:21:46 +080040{
Gao Xianga5876e22019-09-04 10:08:56 +080041 struct erofs_inode *vi = EROFS_I(inode);
Gao Xiangba2b77a2018-07-26 20:21:46 +080042
Gao Xianga2c75c82019-09-04 10:08:59 +080043 /* be careful of RCU symlink path */
44 if (inode->i_op == &erofs_fast_symlink_iops)
Gao Xiangba2b77a2018-07-26 20:21:46 +080045 kfree(inode->i_link);
Gao Xiangba2b77a2018-07-26 20:21:46 +080046 kfree(vi->xattr_shared_xattrs);
47
48 kmem_cache_free(erofs_inode_cachep, vi);
49}
50
Gao Xiang5efe5132019-06-13 16:35:41 +080051static bool check_layout_compatibility(struct super_block *sb,
Gao Xiang0259f202019-09-04 10:09:00 +080052 struct erofs_super_block *dsb)
Gao Xiang5efe5132019-06-13 16:35:41 +080053{
Gao Xiang0259f202019-09-04 10:09:00 +080054 const unsigned int feature = le32_to_cpu(dsb->feature_incompat);
Gao Xiang5efe5132019-06-13 16:35:41 +080055
Gao Xiang426a9302019-09-04 10:08:53 +080056 EROFS_SB(sb)->feature_incompat = feature;
Gao Xiang5efe5132019-06-13 16:35:41 +080057
58 /* check if current kernel meets all mandatory requirements */
Gao Xiang426a9302019-09-04 10:08:53 +080059 if (feature & (~EROFS_ALL_FEATURE_INCOMPAT)) {
60 errln("unidentified incompatible feature %x, please upgrade kernel version",
61 feature & ~EROFS_ALL_FEATURE_INCOMPAT);
Gao Xiang5efe5132019-06-13 16:35:41 +080062 return false;
63 }
64 return true;
65}
66
Gao Xiang99634bf2019-09-04 10:09:05 +080067static int erofs_read_superblock(struct super_block *sb)
Gao Xiangba2b77a2018-07-26 20:21:46 +080068{
69 struct erofs_sb_info *sbi;
70 struct buffer_head *bh;
Gao Xiang0259f202019-09-04 10:09:00 +080071 struct erofs_super_block *dsb;
Thomas Weißschuh7dd68b12018-09-10 21:41:14 +020072 unsigned int blkszbits;
Gao Xiangba2b77a2018-07-26 20:21:46 +080073 int ret;
74
75 bh = sb_bread(sb, 0);
76
Vatsala Narange2ff9f12019-03-21 05:36:13 +053077 if (!bh) {
Gao Xiangba2b77a2018-07-26 20:21:46 +080078 errln("cannot read erofs superblock");
79 return -EIO;
80 }
81
82 sbi = EROFS_SB(sb);
Gao Xiang0259f202019-09-04 10:09:00 +080083 dsb = (struct erofs_super_block *)(bh->b_data + EROFS_SUPER_OFFSET);
Gao Xiangba2b77a2018-07-26 20:21:46 +080084
85 ret = -EINVAL;
Gao Xiang0259f202019-09-04 10:09:00 +080086 if (le32_to_cpu(dsb->magic) != EROFS_SUPER_MAGIC_V1) {
Gao Xiangba2b77a2018-07-26 20:21:46 +080087 errln("cannot find valid erofs superblock");
88 goto out;
89 }
90
Gao Xiang0259f202019-09-04 10:09:00 +080091 blkszbits = dsb->blkszbits;
Gao Xiangba2b77a2018-07-26 20:21:46 +080092 /* 9(512 bytes) + LOG_SECTORS_PER_BLOCK == LOG_BLOCK_SIZE */
Gao Xiang8d8a09b2019-08-30 00:38:27 +080093 if (blkszbits != LOG_BLOCK_SIZE) {
Gao Xiangba2b77a2018-07-26 20:21:46 +080094 errln("blksize %u isn't supported on this platform",
Julian Merida447a3622019-03-18 20:58:41 -030095 1 << blkszbits);
Gao Xiangba2b77a2018-07-26 20:21:46 +080096 goto out;
97 }
98
Gao Xiang0259f202019-09-04 10:09:00 +080099 if (!check_layout_compatibility(sb, dsb))
Gao Xiang5efe5132019-06-13 16:35:41 +0800100 goto out;
101
Gao Xiang0259f202019-09-04 10:09:00 +0800102 sbi->blocks = le32_to_cpu(dsb->blocks);
103 sbi->meta_blkaddr = le32_to_cpu(dsb->meta_blkaddr);
Gao Xiangb17500a2018-07-26 20:21:52 +0800104#ifdef CONFIG_EROFS_FS_XATTR
Gao Xiang0259f202019-09-04 10:09:00 +0800105 sbi->xattr_blkaddr = le32_to_cpu(dsb->xattr_blkaddr);
Gao Xiangb17500a2018-07-26 20:21:52 +0800106#endif
Gao Xiang8a765682019-09-04 10:08:54 +0800107 sbi->islotbits = ilog2(sizeof(struct erofs_inode_compact));
Gao Xiang0259f202019-09-04 10:09:00 +0800108 sbi->root_nid = le16_to_cpu(dsb->root_nid);
109 sbi->inos = le64_to_cpu(dsb->inos);
Gao Xiangba2b77a2018-07-26 20:21:46 +0800110
Gao Xiang0259f202019-09-04 10:09:00 +0800111 sbi->build_time = le64_to_cpu(dsb->build_time);
112 sbi->build_time_nsec = le32_to_cpu(dsb->build_time_nsec);
Gao Xiangba2b77a2018-07-26 20:21:46 +0800113
Gao Xiang0259f202019-09-04 10:09:00 +0800114 memcpy(&sb->s_uuid, dsb->uuid, sizeof(dsb->uuid));
Gao Xiangba2b77a2018-07-26 20:21:46 +0800115
Gao Xiang0259f202019-09-04 10:09:00 +0800116 ret = strscpy(sbi->volume_name, dsb->volume_name,
117 sizeof(dsb->volume_name));
Gao Xianga64d9492019-08-18 18:28:24 +0800118 if (ret < 0) { /* -E2BIG */
119 errln("bad volume name without NIL terminator");
120 ret = -EFSCORRUPTED;
121 goto out;
122 }
Gao Xiangba2b77a2018-07-26 20:21:46 +0800123 ret = 0;
124out:
125 brelse(bh);
126 return ret;
127}
128
Chao Yu9c07b3b2018-07-26 20:21:54 +0800129#ifdef CONFIG_EROFS_FAULT_INJECTION
Gao Xiang14a56ec2019-03-25 11:40:09 +0800130const char *erofs_fault_name[FAULT_MAX] = {
Chao Yu9c07b3b2018-07-26 20:21:54 +0800131 [FAULT_KMALLOC] = "kmalloc",
Gao Xiang14a56ec2019-03-25 11:40:09 +0800132 [FAULT_READ_IO] = "read IO error",
Chao Yu9c07b3b2018-07-26 20:21:54 +0800133};
134
Chengguang Xud41076e2018-09-19 22:53:46 +0800135static void __erofs_build_fault_attr(struct erofs_sb_info *sbi,
136 unsigned int rate)
Chao Yu9c07b3b2018-07-26 20:21:54 +0800137{
138 struct erofs_fault_info *ffi = &sbi->fault_info;
139
140 if (rate) {
141 atomic_set(&ffi->inject_ops, 0);
142 ffi->inject_rate = rate;
143 ffi->inject_type = (1 << FAULT_MAX) - 1;
144 } else {
145 memset(ffi, 0, sizeof(struct erofs_fault_info));
146 }
Chengguang Xu01e4ae42018-09-19 22:53:44 +0800147
148 set_opt(sbi, FAULT_INJECTION);
Chengguang Xud41076e2018-09-19 22:53:46 +0800149}
150
151static int erofs_build_fault_attr(struct erofs_sb_info *sbi,
152 substring_t *args)
153{
154 int rate = 0;
155
156 if (args->from && match_int(args, &rate))
157 return -EINVAL;
158
159 __erofs_build_fault_attr(sbi, rate);
Chengguang Xu01e4ae42018-09-19 22:53:44 +0800160 return 0;
161}
Chengguang Xu2ab3dd82018-09-19 22:53:45 +0800162
163static unsigned int erofs_get_fault_rate(struct erofs_sb_info *sbi)
164{
165 return sbi->fault_info.inject_rate;
166}
Chengguang Xu01e4ae42018-09-19 22:53:44 +0800167#else
Chengguang Xud41076e2018-09-19 22:53:46 +0800168static void __erofs_build_fault_attr(struct erofs_sb_info *sbi,
169 unsigned int rate)
170{
171}
172
Chengguang Xu01e4ae42018-09-19 22:53:44 +0800173static int erofs_build_fault_attr(struct erofs_sb_info *sbi,
174 substring_t *args)
175{
176 infoln("fault_injection options not supported");
177 return 0;
Chao Yu9c07b3b2018-07-26 20:21:54 +0800178}
Chengguang Xu2ab3dd82018-09-19 22:53:45 +0800179
180static unsigned int erofs_get_fault_rate(struct erofs_sb_info *sbi)
181{
182 return 0;
183}
Chao Yu9c07b3b2018-07-26 20:21:54 +0800184#endif
185
Gao Xiang5fb76bb2018-09-20 00:06:56 +0800186#ifdef CONFIG_EROFS_FS_ZIP
Gao Xiang4279f3f2019-07-31 23:57:49 +0800187static int erofs_build_cache_strategy(struct erofs_sb_info *sbi,
188 substring_t *args)
189{
190 const char *cs = match_strdup(args);
191 int err = 0;
192
193 if (!cs) {
194 errln("Not enough memory to store cache strategy");
195 return -ENOMEM;
196 }
197
198 if (!strcmp(cs, "disabled")) {
199 sbi->cache_strategy = EROFS_ZIP_CACHE_DISABLED;
200 } else if (!strcmp(cs, "readahead")) {
201 sbi->cache_strategy = EROFS_ZIP_CACHE_READAHEAD;
202 } else if (!strcmp(cs, "readaround")) {
203 sbi->cache_strategy = EROFS_ZIP_CACHE_READAROUND;
204 } else {
205 errln("Unrecognized cache strategy \"%s\"", cs);
206 err = -EINVAL;
207 }
208 kfree(cs);
209 return err;
210}
211#else
212static int erofs_build_cache_strategy(struct erofs_sb_info *sbi,
213 substring_t *args)
214{
215 infoln("EROFS compression is disabled, so cache strategy is ignored");
216 return 0;
217}
Gao Xiang5fb76bb2018-09-20 00:06:56 +0800218#endif
219
Gao Xiang4279f3f2019-07-31 23:57:49 +0800220/* set up default EROFS parameters */
Gao Xiang99634bf2019-09-04 10:09:05 +0800221static void erofs_default_options(struct erofs_sb_info *sbi)
Gao Xiang4279f3f2019-07-31 23:57:49 +0800222{
223#ifdef CONFIG_EROFS_FS_ZIP
224 sbi->cache_strategy = EROFS_ZIP_CACHE_READAROUND;
225 sbi->max_sync_decompress_pages = 3;
226#endif
Gao Xiangb17500a2018-07-26 20:21:52 +0800227#ifdef CONFIG_EROFS_FS_XATTR
228 set_opt(sbi, XATTR_USER);
229#endif
Gao Xiangb17500a2018-07-26 20:21:52 +0800230#ifdef CONFIG_EROFS_FS_POSIX_ACL
231 set_opt(sbi, POSIX_ACL);
232#endif
Gao Xiangba2b77a2018-07-26 20:21:46 +0800233}
234
235enum {
Gao Xiangb17500a2018-07-26 20:21:52 +0800236 Opt_user_xattr,
237 Opt_nouser_xattr,
238 Opt_acl,
239 Opt_noacl,
Chao Yu9c07b3b2018-07-26 20:21:54 +0800240 Opt_fault_injection,
Gao Xiang4279f3f2019-07-31 23:57:49 +0800241 Opt_cache_strategy,
Gao Xiangba2b77a2018-07-26 20:21:46 +0800242 Opt_err
243};
244
245static match_table_t erofs_tokens = {
Gao Xiangb17500a2018-07-26 20:21:52 +0800246 {Opt_user_xattr, "user_xattr"},
247 {Opt_nouser_xattr, "nouser_xattr"},
248 {Opt_acl, "acl"},
249 {Opt_noacl, "noacl"},
Chao Yu9c07b3b2018-07-26 20:21:54 +0800250 {Opt_fault_injection, "fault_injection=%u"},
Gao Xiang4279f3f2019-07-31 23:57:49 +0800251 {Opt_cache_strategy, "cache_strategy=%s"},
Gao Xiangba2b77a2018-07-26 20:21:46 +0800252 {Opt_err, NULL}
253};
254
Gao Xiang99634bf2019-09-04 10:09:05 +0800255static int erofs_parse_options(struct super_block *sb, char *options)
Gao Xiangba2b77a2018-07-26 20:21:46 +0800256{
257 substring_t args[MAX_OPT_ARGS];
258 char *p;
Chengguang Xu01e4ae42018-09-19 22:53:44 +0800259 int err;
Gao Xiangba2b77a2018-07-26 20:21:46 +0800260
261 if (!options)
262 return 0;
263
Bhanusree Pola561fb352019-03-22 10:38:16 +0800264 while ((p = strsep(&options, ","))) {
Gao Xiangba2b77a2018-07-26 20:21:46 +0800265 int token;
266
267 if (!*p)
268 continue;
269
270 args[0].to = args[0].from = NULL;
271 token = match_token(p, erofs_tokens, args);
272
273 switch (token) {
Gao Xiangb17500a2018-07-26 20:21:52 +0800274#ifdef CONFIG_EROFS_FS_XATTR
275 case Opt_user_xattr:
276 set_opt(EROFS_SB(sb), XATTR_USER);
277 break;
278 case Opt_nouser_xattr:
279 clear_opt(EROFS_SB(sb), XATTR_USER);
280 break;
281#else
282 case Opt_user_xattr:
283 infoln("user_xattr options not supported");
284 break;
285 case Opt_nouser_xattr:
286 infoln("nouser_xattr options not supported");
287 break;
288#endif
289#ifdef CONFIG_EROFS_FS_POSIX_ACL
290 case Opt_acl:
291 set_opt(EROFS_SB(sb), POSIX_ACL);
292 break;
293 case Opt_noacl:
294 clear_opt(EROFS_SB(sb), POSIX_ACL);
295 break;
296#else
297 case Opt_acl:
298 infoln("acl options not supported");
299 break;
300 case Opt_noacl:
301 infoln("noacl options not supported");
302 break;
303#endif
Chao Yu9c07b3b2018-07-26 20:21:54 +0800304 case Opt_fault_injection:
Chengguang Xu01e4ae42018-09-19 22:53:44 +0800305 err = erofs_build_fault_attr(EROFS_SB(sb), args);
306 if (err)
307 return err;
Chao Yu9c07b3b2018-07-26 20:21:54 +0800308 break;
Gao Xiang4279f3f2019-07-31 23:57:49 +0800309 case Opt_cache_strategy:
310 err = erofs_build_cache_strategy(EROFS_SB(sb), args);
311 if (err)
312 return err;
313 break;
Gao Xiangba2b77a2018-07-26 20:21:46 +0800314 default:
Gao Xiangbc33d9f2019-07-31 23:57:51 +0800315 errln("Unrecognized mount option \"%s\" or missing value", p);
Gao Xiangba2b77a2018-07-26 20:21:46 +0800316 return -EINVAL;
317 }
318 }
319 return 0;
320}
321
Gao Xiang4279f3f2019-07-31 23:57:49 +0800322#ifdef CONFIG_EROFS_FS_ZIP
Gao Xiang105d4ad2018-07-26 20:22:07 +0800323static const struct address_space_operations managed_cache_aops;
324
Gao Xiang99634bf2019-09-04 10:09:05 +0800325static int erofs_managed_cache_releasepage(struct page *page, gfp_t gfp_mask)
Gao Xiang105d4ad2018-07-26 20:22:07 +0800326{
327 int ret = 1; /* 0 - busy */
328 struct address_space *const mapping = page->mapping;
329
Gao Xiang8b987bc2018-12-05 21:23:13 +0800330 DBG_BUGON(!PageLocked(page));
331 DBG_BUGON(mapping->a_ops != &managed_cache_aops);
Gao Xiang105d4ad2018-07-26 20:22:07 +0800332
333 if (PagePrivate(page))
Gao Xiang47e541a2018-07-29 13:34:58 +0800334 ret = erofs_try_to_free_cached_page(mapping, page);
Gao Xiang105d4ad2018-07-26 20:22:07 +0800335
336 return ret;
337}
338
Gao Xiang99634bf2019-09-04 10:09:05 +0800339static void erofs_managed_cache_invalidatepage(struct page *page,
340 unsigned int offset,
341 unsigned int length)
Gao Xiang105d4ad2018-07-26 20:22:07 +0800342{
343 const unsigned int stop = length + offset;
344
Gao Xiang8b987bc2018-12-05 21:23:13 +0800345 DBG_BUGON(!PageLocked(page));
Gao Xiang105d4ad2018-07-26 20:22:07 +0800346
Gao Xiang8b987bc2018-12-05 21:23:13 +0800347 /* Check for potential overflow in debug mode */
348 DBG_BUGON(stop > PAGE_SIZE || stop < length);
Gao Xiang105d4ad2018-07-26 20:22:07 +0800349
350 if (offset == 0 && stop == PAGE_SIZE)
Gao Xiang99634bf2019-09-04 10:09:05 +0800351 while (!erofs_managed_cache_releasepage(page, GFP_NOFS))
Gao Xiang105d4ad2018-07-26 20:22:07 +0800352 cond_resched();
353}
354
355static const struct address_space_operations managed_cache_aops = {
Gao Xiang99634bf2019-09-04 10:09:05 +0800356 .releasepage = erofs_managed_cache_releasepage,
357 .invalidatepage = erofs_managed_cache_invalidatepage,
Gao Xiang105d4ad2018-07-26 20:22:07 +0800358};
359
Gao Xiang8f7acda2019-07-31 23:57:41 +0800360static int erofs_init_managed_cache(struct super_block *sb)
Gao Xiang105d4ad2018-07-26 20:22:07 +0800361{
Gao Xiang8f7acda2019-07-31 23:57:41 +0800362 struct erofs_sb_info *const sbi = EROFS_SB(sb);
363 struct inode *const inode = new_inode(sb);
Gao Xiang105d4ad2018-07-26 20:22:07 +0800364
Gao Xiang8d8a09b2019-08-30 00:38:27 +0800365 if (!inode)
Gao Xiang8f7acda2019-07-31 23:57:41 +0800366 return -ENOMEM;
Gao Xiang105d4ad2018-07-26 20:22:07 +0800367
368 set_nlink(inode, 1);
369 inode->i_size = OFFSET_MAX;
370
371 inode->i_mapping->a_ops = &managed_cache_aops;
372 mapping_set_gfp_mask(inode->i_mapping,
Gao Xiang8494c292019-07-31 23:57:42 +0800373 GFP_NOFS | __GFP_HIGHMEM | __GFP_MOVABLE);
Gao Xiang8f7acda2019-07-31 23:57:41 +0800374 sbi->managed_cache = inode;
375 return 0;
Gao Xiang105d4ad2018-07-26 20:22:07 +0800376}
Gao Xiang8f7acda2019-07-31 23:57:41 +0800377#else
378static int erofs_init_managed_cache(struct super_block *sb) { return 0; }
Gao Xiang105d4ad2018-07-26 20:22:07 +0800379#endif
380
Gao Xiang9e794de2019-07-31 23:57:40 +0800381static int erofs_fill_super(struct super_block *sb, void *data, int silent)
Gao Xiangba2b77a2018-07-26 20:21:46 +0800382{
383 struct inode *inode;
384 struct erofs_sb_info *sbi;
Gao Xiang8f7acda2019-07-31 23:57:41 +0800385 int err;
Gao Xiangba2b77a2018-07-26 20:21:46 +0800386
Gao Xiang8f7acda2019-07-31 23:57:41 +0800387 sb->s_magic = EROFS_SUPER_MAGIC;
388
Gao Xiang8d8a09b2019-08-30 00:38:27 +0800389 if (!sb_set_blocksize(sb, EROFS_BLKSIZ)) {
Gao Xiangba2b77a2018-07-26 20:21:46 +0800390 errln("failed to set erofs blksize");
Gao Xiang8f7acda2019-07-31 23:57:41 +0800391 return -EINVAL;
Gao Xiangba2b77a2018-07-26 20:21:46 +0800392 }
393
Shobhit Kukretia9f69bd2019-06-26 22:31:18 -0700394 sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
Gao Xiang8d8a09b2019-08-30 00:38:27 +0800395 if (!sbi)
Gao Xiang8f7acda2019-07-31 23:57:41 +0800396 return -ENOMEM;
Gao Xiangba2b77a2018-07-26 20:21:46 +0800397
Gao Xiang8f7acda2019-07-31 23:57:41 +0800398 sb->s_fs_info = sbi;
Gao Xiang99634bf2019-09-04 10:09:05 +0800399 err = erofs_read_superblock(sb);
Gao Xiangba2b77a2018-07-26 20:21:46 +0800400 if (err)
Gao Xiang8f7acda2019-07-31 23:57:41 +0800401 return err;
Gao Xiangba2b77a2018-07-26 20:21:46 +0800402
Gao Xiang5f0abea2018-09-06 17:01:47 +0800403 sb->s_flags |= SB_RDONLY | SB_NOATIME;
Gao Xiangba2b77a2018-07-26 20:21:46 +0800404 sb->s_maxbytes = MAX_LFS_FILESIZE;
405 sb->s_time_gran = 1;
406
407 sb->s_op = &erofs_sops;
408
Gao Xiangb17500a2018-07-26 20:21:52 +0800409#ifdef CONFIG_EROFS_FS_XATTR
410 sb->s_xattr = erofs_xattr_handlers;
411#endif
Gao Xiangba2b77a2018-07-26 20:21:46 +0800412 /* set erofs default mount options */
Gao Xiang99634bf2019-09-04 10:09:05 +0800413 erofs_default_options(sbi);
Gao Xiangba2b77a2018-07-26 20:21:46 +0800414
Gao Xiang99634bf2019-09-04 10:09:05 +0800415 err = erofs_parse_options(sb, data);
Gao Xiang8d8a09b2019-08-30 00:38:27 +0800416 if (err)
Gao Xiang8f7acda2019-07-31 23:57:41 +0800417 return err;
Gao Xiangba2b77a2018-07-26 20:21:46 +0800418
Gao Xiang516c115c2019-01-29 16:35:20 +0800419 if (test_opt(sbi, POSIX_ACL))
420 sb->s_flags |= SB_POSIXACL;
421 else
422 sb->s_flags &= ~SB_POSIXACL;
423
Gao Xiange7e9a302018-07-26 20:22:05 +0800424#ifdef CONFIG_EROFS_FS_ZIP
425 INIT_RADIX_TREE(&sbi->workstn_tree, GFP_ATOMIC);
426#endif
427
Gao Xiangba2b77a2018-07-26 20:21:46 +0800428 /* get the root inode */
429 inode = erofs_iget(sb, ROOT_NID(sbi), true);
Gao Xiang8f7acda2019-07-31 23:57:41 +0800430 if (IS_ERR(inode))
431 return PTR_ERR(inode);
Gao Xiangba2b77a2018-07-26 20:21:46 +0800432
Gao Xiang8d8a09b2019-08-30 00:38:27 +0800433 if (!S_ISDIR(inode->i_mode)) {
Gao Xiangba2b77a2018-07-26 20:21:46 +0800434 errln("rootino(nid %llu) is not a directory(i_mode %o)",
Julian Merida447a3622019-03-18 20:58:41 -0300435 ROOT_NID(sbi), inode->i_mode);
Chengguang Xu94832d92019-01-23 14:12:25 +0800436 iput(inode);
Gao Xiang8f7acda2019-07-31 23:57:41 +0800437 return -EINVAL;
Gao Xiangba2b77a2018-07-26 20:21:46 +0800438 }
439
440 sb->s_root = d_make_root(inode);
Gao Xiang8d8a09b2019-08-30 00:38:27 +0800441 if (!sb->s_root)
Gao Xiang8f7acda2019-07-31 23:57:41 +0800442 return -ENOMEM;
Gao Xiangba2b77a2018-07-26 20:21:46 +0800443
Gao Xiang22fe04a2019-07-31 23:57:39 +0800444 erofs_shrinker_register(sb);
Gao Xiang8f7acda2019-07-31 23:57:41 +0800445 /* sb->s_umount is already locked, SB_ACTIVE and SB_BORN are not set */
446 err = erofs_init_managed_cache(sb);
Gao Xiang8d8a09b2019-08-30 00:38:27 +0800447 if (err)
Gao Xiang8f7acda2019-07-31 23:57:41 +0800448 return err;
Gao Xiang2497ee42018-07-26 20:22:03 +0800449
Gao Xiangba2b77a2018-07-26 20:21:46 +0800450 if (!silent)
Gao Xiang688a5f22019-09-04 10:09:01 +0800451 infoln("mounted on %s with opts: %s, root inode @ nid %llu.",
452 sb->s_id, (char *)data, ROOT_NID(sbi));
Gao Xiangba2b77a2018-07-26 20:21:46 +0800453 return 0;
Gao Xiangba2b77a2018-07-26 20:21:46 +0800454}
455
Gao Xiang9e794de2019-07-31 23:57:40 +0800456static struct dentry *erofs_mount(struct file_system_type *fs_type, int flags,
457 const char *dev_name, void *data)
Gao Xiangba2b77a2018-07-26 20:21:46 +0800458{
Gao Xiang9e794de2019-07-31 23:57:40 +0800459 return mount_bdev(fs_type, flags, dev_name, data, erofs_fill_super);
Gao Xiangba2b77a2018-07-26 20:21:46 +0800460}
461
Gao Xiang8f7acda2019-07-31 23:57:41 +0800462/*
463 * could be triggered after deactivate_locked_super()
464 * is called, thus including umount and failed to initialize.
465 */
466static void erofs_kill_sb(struct super_block *sb)
467{
468 struct erofs_sb_info *sbi;
469
470 WARN_ON(sb->s_magic != EROFS_SUPER_MAGIC);
471 infoln("unmounting for %s", sb->s_id);
472
473 kill_block_super(sb);
474
475 sbi = EROFS_SB(sb);
476 if (!sbi)
477 return;
478 kfree(sbi);
479 sb->s_fs_info = NULL;
480}
481
482/* called when ->s_root is non-NULL */
483static void erofs_put_super(struct super_block *sb)
484{
485 struct erofs_sb_info *const sbi = EROFS_SB(sb);
486
487 DBG_BUGON(!sbi);
488
489 erofs_shrinker_unregister(sb);
Gao Xiang4279f3f2019-07-31 23:57:49 +0800490#ifdef CONFIG_EROFS_FS_ZIP
Gao Xiang8f7acda2019-07-31 23:57:41 +0800491 iput(sbi->managed_cache);
492 sbi->managed_cache = NULL;
493#endif
494}
495
Gao Xiangba2b77a2018-07-26 20:21:46 +0800496static struct file_system_type erofs_fs_type = {
497 .owner = THIS_MODULE,
498 .name = "erofs",
499 .mount = erofs_mount,
Gao Xiang8f7acda2019-07-31 23:57:41 +0800500 .kill_sb = erofs_kill_sb,
Gao Xiangba2b77a2018-07-26 20:21:46 +0800501 .fs_flags = FS_REQUIRES_DEV,
502};
503MODULE_ALIAS_FS("erofs");
504
505static int __init erofs_module_init(void)
506{
507 int err;
508
509 erofs_check_ondisk_layout_definitions();
510 infoln("initializing erofs " EROFS_VERSION);
511
Gao Xiang1c2dfbf2019-09-04 10:08:55 +0800512 erofs_inode_cachep = kmem_cache_create("erofs_inode",
Gao Xianga5876e22019-09-04 10:08:56 +0800513 sizeof(struct erofs_inode), 0,
Gao Xiang1c2dfbf2019-09-04 10:08:55 +0800514 SLAB_RECLAIM_ACCOUNT,
Gao Xiang99634bf2019-09-04 10:09:05 +0800515 erofs_inode_init_once);
Gao Xiang1c2dfbf2019-09-04 10:08:55 +0800516 if (!erofs_inode_cachep) {
517 err = -ENOMEM;
Gao Xiangba2b77a2018-07-26 20:21:46 +0800518 goto icache_err;
Gao Xiang1c2dfbf2019-09-04 10:08:55 +0800519 }
Gao Xiangba2b77a2018-07-26 20:21:46 +0800520
Gao Xiang22fe04a2019-07-31 23:57:39 +0800521 err = erofs_init_shrinker();
Gao Xianga1581312018-07-26 20:22:04 +0800522 if (err)
523 goto shrinker_err;
524
Gao Xiang3883a792018-07-26 20:22:06 +0800525 err = z_erofs_init_zip_subsystem();
526 if (err)
527 goto zip_err;
Gao Xiang3883a792018-07-26 20:22:06 +0800528
Gao Xiangba2b77a2018-07-26 20:21:46 +0800529 err = register_filesystem(&erofs_fs_type);
530 if (err)
531 goto fs_err;
532
533 infoln("successfully to initialize erofs");
534 return 0;
535
536fs_err:
Gao Xiang3883a792018-07-26 20:22:06 +0800537 z_erofs_exit_zip_subsystem();
538zip_err:
Gao Xiang22fe04a2019-07-31 23:57:39 +0800539 erofs_exit_shrinker();
Gao Xianga1581312018-07-26 20:22:04 +0800540shrinker_err:
Gao Xiang1c2dfbf2019-09-04 10:08:55 +0800541 kmem_cache_destroy(erofs_inode_cachep);
Gao Xiangba2b77a2018-07-26 20:21:46 +0800542icache_err:
543 return err;
544}
545
546static void __exit erofs_module_exit(void)
547{
548 unregister_filesystem(&erofs_fs_type);
Gao Xiang3883a792018-07-26 20:22:06 +0800549 z_erofs_exit_zip_subsystem();
Gao Xiang22fe04a2019-07-31 23:57:39 +0800550 erofs_exit_shrinker();
Gao Xiang1c2dfbf2019-09-04 10:08:55 +0800551
552 /* Ensure all RCU free inodes are safe before cache is destroyed. */
553 rcu_barrier();
554 kmem_cache_destroy(erofs_inode_cachep);
Gao Xiangba2b77a2018-07-26 20:21:46 +0800555 infoln("successfully finalize erofs");
556}
557
558/* get filesystem statistics */
559static int erofs_statfs(struct dentry *dentry, struct kstatfs *buf)
560{
561 struct super_block *sb = dentry->d_sb;
562 struct erofs_sb_info *sbi = EROFS_SB(sb);
563 u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
564
565 buf->f_type = sb->s_magic;
566 buf->f_bsize = EROFS_BLKSIZ;
567 buf->f_blocks = sbi->blocks;
568 buf->f_bfree = buf->f_bavail = 0;
569
570 buf->f_files = ULLONG_MAX;
571 buf->f_ffree = ULLONG_MAX - sbi->inos;
572
573 buf->f_namelen = EROFS_NAME_LEN;
574
575 buf->f_fsid.val[0] = (u32)id;
576 buf->f_fsid.val[1] = (u32)(id >> 32);
577 return 0;
578}
579
580static int erofs_show_options(struct seq_file *seq, struct dentry *root)
581{
Gao Xiangb17500a2018-07-26 20:21:52 +0800582 struct erofs_sb_info *sbi __maybe_unused = EROFS_SB(root->d_sb);
583
584#ifdef CONFIG_EROFS_FS_XATTR
585 if (test_opt(sbi, XATTR_USER))
586 seq_puts(seq, ",user_xattr");
587 else
588 seq_puts(seq, ",nouser_xattr");
589#endif
590#ifdef CONFIG_EROFS_FS_POSIX_ACL
591 if (test_opt(sbi, POSIX_ACL))
592 seq_puts(seq, ",acl");
593 else
594 seq_puts(seq, ",noacl");
595#endif
Chao Yu9c07b3b2018-07-26 20:21:54 +0800596 if (test_opt(sbi, FAULT_INJECTION))
597 seq_printf(seq, ",fault_injection=%u",
Julian Merida447a3622019-03-18 20:58:41 -0300598 erofs_get_fault_rate(sbi));
Gao Xiang4279f3f2019-07-31 23:57:49 +0800599#ifdef CONFIG_EROFS_FS_ZIP
600 if (sbi->cache_strategy == EROFS_ZIP_CACHE_DISABLED) {
601 seq_puts(seq, ",cache_strategy=disabled");
602 } else if (sbi->cache_strategy == EROFS_ZIP_CACHE_READAHEAD) {
603 seq_puts(seq, ",cache_strategy=readahead");
604 } else if (sbi->cache_strategy == EROFS_ZIP_CACHE_READAROUND) {
605 seq_puts(seq, ",cache_strategy=readaround");
606 } else {
607 seq_puts(seq, ",cache_strategy=(unknown)");
608 DBG_BUGON(1);
609 }
610#endif
Gao Xiangba2b77a2018-07-26 20:21:46 +0800611 return 0;
612}
613
614static int erofs_remount(struct super_block *sb, int *flags, char *data)
615{
Chengguang Xud41076e2018-09-19 22:53:46 +0800616 struct erofs_sb_info *sbi = EROFS_SB(sb);
617 unsigned int org_mnt_opt = sbi->mount_opt;
618 unsigned int org_inject_rate = erofs_get_fault_rate(sbi);
619 int err;
620
Gao Xiang8b987bc2018-12-05 21:23:13 +0800621 DBG_BUGON(!sb_rdonly(sb));
Gao Xiang99634bf2019-09-04 10:09:05 +0800622 err = erofs_parse_options(sb, data);
Chengguang Xud41076e2018-09-19 22:53:46 +0800623 if (err)
624 goto out;
Gao Xiangba2b77a2018-07-26 20:21:46 +0800625
Gao Xiang516c115c2019-01-29 16:35:20 +0800626 if (test_opt(sbi, POSIX_ACL))
627 sb->s_flags |= SB_POSIXACL;
628 else
629 sb->s_flags &= ~SB_POSIXACL;
630
Gao Xiang5f0abea2018-09-06 17:01:47 +0800631 *flags |= SB_RDONLY;
Gao Xiangba2b77a2018-07-26 20:21:46 +0800632 return 0;
Chengguang Xud41076e2018-09-19 22:53:46 +0800633out:
634 __erofs_build_fault_attr(sbi, org_inject_rate);
635 sbi->mount_opt = org_mnt_opt;
636
637 return err;
Gao Xiangba2b77a2018-07-26 20:21:46 +0800638}
639
640const struct super_operations erofs_sops = {
641 .put_super = erofs_put_super,
Gao Xiang99634bf2019-09-04 10:09:05 +0800642 .alloc_inode = erofs_alloc_inode,
643 .free_inode = erofs_free_inode,
Gao Xiangba2b77a2018-07-26 20:21:46 +0800644 .statfs = erofs_statfs,
645 .show_options = erofs_show_options,
646 .remount_fs = erofs_remount,
647};
648
649module_init(erofs_module_init);
650module_exit(erofs_module_exit);
651
652MODULE_DESCRIPTION("Enhanced ROM File System");
Gao Xiangbc33d9f2019-07-31 23:57:51 +0800653MODULE_AUTHOR("Gao Xiang, Chao Yu, Miao Xie, CONSUMER BG, HUAWEI Inc.");
Gao Xiangba2b77a2018-07-26 20:21:46 +0800654MODULE_LICENSE("GPL");
655