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