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 15enum { 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 29static 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 45void __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 62static 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 77int 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 } 170out: 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