1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * fs/hmdfs/super.c
4 *
5 * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
6 */
7
8 #include <linux/backing-dev-defs.h>
9 #include <linux/ratelimit.h>
10 #include <linux/parser.h>
11 #include <linux/slab.h>
12
13 #include "hmdfs.h"
14
15 enum {
16 OPT_RA_PAGES,
17 OPT_LOCAL_DST,
18 OPT_CACHE_DIR,
19 OPT_CLOUD_DIR,
20 OPT_S_CASE,
21 OPT_VIEW_TYPE,
22 OPT_CLOUD_DISK_TYPE,
23 OPT_NO_OFFLINE_STASH,
24 OPT_NO_DENTRY_CACHE,
25 OPT_USER_ID,
26 OPT_DEVELOPER,
27 OPT_ERR,
28 };
29
30 static match_table_t hmdfs_tokens = {
31 { OPT_RA_PAGES, "ra_pages=%s" },
32 { OPT_LOCAL_DST, "local_dst=%s" },
33 { OPT_CACHE_DIR, "cache_dir=%s" },
34 { OPT_CLOUD_DIR, "cloud_dir=%s" },
35 { OPT_S_CASE, "sensitive" },
36 { OPT_VIEW_TYPE, "merge" },
37 { OPT_CLOUD_DISK_TYPE, "cloud_disk"},
38 { OPT_NO_OFFLINE_STASH, "no_offline_stash" },
39 { OPT_NO_DENTRY_CACHE, "no_dentry_cache" },
40 { OPT_USER_ID, "user_id=%s"},
41 { OPT_DEVELOPER, "developer"},
42 { OPT_ERR, NULL },
43 };
44
45 #define DEAULT_RA_PAGES 128
46
__hmdfs_log(const char * level,const bool ratelimited,const char * function,const char * fmt,...)47 void __hmdfs_log(const char *level, const bool ratelimited,
48 const char *function, const char *fmt, ...)
49 {
50 struct va_format vaf;
51 va_list args;
52
53 va_start(args, fmt);
54 vaf.fmt = fmt;
55 vaf.va = &args;
56 if (ratelimited)
57 printk_ratelimited("%s hmdfs: %s() %pV\n", level,
58 function, &vaf);
59 else
60 printk("%s hmdfs: %s() %pV\n", level, function, &vaf);
61 va_end(args);
62 }
63
hmdfs_match_strdup(const substring_t * s,char ** dst)64 static int hmdfs_match_strdup(const substring_t *s, char **dst)
65 {
66 char *dup = NULL;
67
68 dup = match_strdup(s);
69 if (!dup)
70 return -ENOMEM;
71
72 if (*dst)
73 kfree(*dst);
74 *dst = dup;
75
76 return 0;
77 }
78
hmdfs_parse_options(struct hmdfs_sb_info * sbi,const char * data)79 int hmdfs_parse_options(struct hmdfs_sb_info *sbi, const char *data)
80 {
81 char *p = NULL;
82 char *name = NULL;
83 char *options = NULL;
84 char *options_src = NULL;
85 substring_t args[MAX_OPT_ARGS];
86 unsigned long value = DEAULT_RA_PAGES;
87 unsigned int user_id = 0;
88 struct super_block *sb = sbi->sb;
89 int err = 0;
90 size_t size = 0;
91
92 size = strlen(data);
93 if (size >= HMDFS_PAGE_SIZE) {
94 return -EINVAL;
95 }
96
97 options = kstrdup(data, GFP_KERNEL);
98 if (data && !options) {
99 err = -ENOMEM;
100 goto out;
101 }
102 options_src = options;
103 err = super_setup_bdi(sb);
104 if (err)
105 goto out;
106
107 while ((p = strsep(&options_src, ",")) != NULL) {
108 int token;
109
110 if (!*p)
111 continue;
112 args[0].to = args[0].from = NULL;
113 token = match_token(p, hmdfs_tokens, args);
114
115 switch (token) {
116 case OPT_RA_PAGES:
117 name = match_strdup(&args[0]);
118 if (name) {
119 err = kstrtoul(name, 10, &value);
120 kfree(name);
121 name = NULL;
122 if (err)
123 goto out;
124 }
125 break;
126 case OPT_LOCAL_DST:
127 err = hmdfs_match_strdup(&args[0], &sbi->local_dst);
128 if (err)
129 goto out;
130 break;
131 case OPT_CACHE_DIR:
132 err = hmdfs_match_strdup(&args[0], &sbi->cache_dir);
133 if (err)
134 goto out;
135 break;
136 case OPT_CLOUD_DIR:
137 err = hmdfs_match_strdup(&args[0], &sbi->cloud_dir);
138 if (err)
139 goto out;
140 break;
141 case OPT_S_CASE:
142 sbi->s_case_sensitive = true;
143 break;
144 case OPT_VIEW_TYPE:
145 sbi->s_merge_switch = true;
146 break;
147 case OPT_CLOUD_DISK_TYPE:
148 sbi->s_cloud_disk_switch = true;
149 break;
150 case OPT_NO_OFFLINE_STASH:
151 sbi->s_offline_stash = false;
152 break;
153 case OPT_NO_DENTRY_CACHE:
154 sbi->s_dentry_cache = false;
155 break;
156 case OPT_USER_ID:
157 name = match_strdup(&args[0]);
158 if (name) {
159 err = kstrtouint(name, 10, &user_id);
160 kfree(name);
161 name = NULL;
162 if (err)
163 goto out;
164 sbi->user_id = user_id;
165 }
166 break;
167 case OPT_DEVELOPER:
168 break;
169 default:
170 err = -EINVAL;
171 goto out;
172 }
173 }
174 out:
175 kfree(options);
176 sb->s_bdi->ra_pages = value;
177 if (sbi->local_dst == NULL)
178 err = -EINVAL;
179
180 if (sbi->s_offline_stash && !sbi->cache_dir) {
181 hmdfs_warning("no cache_dir for offline stash");
182 sbi->s_offline_stash = false;
183 }
184
185 if (sbi->s_dentry_cache && !sbi->cache_dir) {
186 hmdfs_warning("no cache_dir for dentry cache");
187 sbi->s_dentry_cache = false;
188 }
189
190 return err;
191 }
192