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