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