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