.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | |
---|
2 | 3 | #include <linux/ceph/ceph_debug.h> |
---|
3 | 4 | |
---|
.. | .. |
---|
8 | 9 | #include <linux/in6.h> |
---|
9 | 10 | #include <linux/module.h> |
---|
10 | 11 | #include <linux/mount.h> |
---|
11 | | -#include <linux/parser.h> |
---|
| 12 | +#include <linux/fs_context.h> |
---|
| 13 | +#include <linux/fs_parser.h> |
---|
12 | 14 | #include <linux/sched.h> |
---|
13 | 15 | #include <linux/seq_file.h> |
---|
14 | 16 | #include <linux/slab.h> |
---|
.. | .. |
---|
24 | 26 | #include <linux/ceph/mon_client.h> |
---|
25 | 27 | #include <linux/ceph/auth.h> |
---|
26 | 28 | #include <linux/ceph/debugfs.h> |
---|
| 29 | + |
---|
| 30 | +static DEFINE_SPINLOCK(ceph_fsc_lock); |
---|
| 31 | +static LIST_HEAD(ceph_fsc_list); |
---|
27 | 32 | |
---|
28 | 33 | /* |
---|
29 | 34 | * Ceph superblock operations |
---|
.. | .. |
---|
47 | 52 | struct ceph_fs_client *fsc = ceph_inode_to_client(d_inode(dentry)); |
---|
48 | 53 | struct ceph_mon_client *monc = &fsc->client->monc; |
---|
49 | 54 | struct ceph_statfs st; |
---|
50 | | - u64 fsid; |
---|
51 | | - int err; |
---|
| 55 | + int i, err; |
---|
52 | 56 | u64 data_pool; |
---|
53 | 57 | |
---|
54 | 58 | if (fsc->mdsc->mdsmap->m_num_data_pg_pools == 1) { |
---|
.. | .. |
---|
94 | 98 | buf->f_namelen = NAME_MAX; |
---|
95 | 99 | |
---|
96 | 100 | /* Must convert the fsid, for consistent values across arches */ |
---|
| 101 | + buf->f_fsid.val[0] = 0; |
---|
97 | 102 | mutex_lock(&monc->mutex); |
---|
98 | | - fsid = le64_to_cpu(*(__le64 *)(&monc->monmap->fsid)) ^ |
---|
99 | | - le64_to_cpu(*((__le64 *)&monc->monmap->fsid + 1)); |
---|
| 103 | + for (i = 0 ; i < sizeof(monc->monmap->fsid) / sizeof(__le32) ; ++i) |
---|
| 104 | + buf->f_fsid.val[0] ^= le32_to_cpu(((__le32 *)&monc->monmap->fsid)[i]); |
---|
100 | 105 | mutex_unlock(&monc->mutex); |
---|
101 | 106 | |
---|
102 | | - buf->f_fsid.val[0] = fsid & 0xffffffff; |
---|
103 | | - buf->f_fsid.val[1] = fsid >> 32; |
---|
| 107 | + /* fold the fs_cluster_id into the upper bits */ |
---|
| 108 | + buf->f_fsid.val[1] = monc->fs_cluster_id; |
---|
104 | 109 | |
---|
105 | 110 | return 0; |
---|
106 | 111 | } |
---|
.. | .. |
---|
132 | 137 | Opt_rasize, |
---|
133 | 138 | Opt_caps_wanted_delay_min, |
---|
134 | 139 | Opt_caps_wanted_delay_max, |
---|
| 140 | + Opt_caps_max, |
---|
135 | 141 | Opt_readdir_max_entries, |
---|
136 | 142 | Opt_readdir_max_bytes, |
---|
137 | 143 | Opt_congestion_kb, |
---|
138 | | - Opt_last_int, |
---|
139 | 144 | /* int args above */ |
---|
140 | 145 | Opt_snapdirname, |
---|
141 | 146 | Opt_mds_namespace, |
---|
142 | | - Opt_fscache_uniq, |
---|
143 | | - Opt_last_string, |
---|
| 147 | + Opt_recover_session, |
---|
| 148 | + Opt_source, |
---|
144 | 149 | /* string args above */ |
---|
145 | 150 | Opt_dirstat, |
---|
146 | | - Opt_nodirstat, |
---|
147 | 151 | Opt_rbytes, |
---|
148 | | - Opt_norbytes, |
---|
149 | 152 | Opt_asyncreaddir, |
---|
150 | | - Opt_noasyncreaddir, |
---|
151 | 153 | Opt_dcache, |
---|
152 | | - Opt_nodcache, |
---|
153 | 154 | Opt_ino32, |
---|
154 | | - Opt_noino32, |
---|
155 | 155 | Opt_fscache, |
---|
156 | | - Opt_nofscache, |
---|
157 | 156 | Opt_poolperm, |
---|
158 | | - Opt_nopoolperm, |
---|
159 | 157 | Opt_require_active_mds, |
---|
160 | | - Opt_norequire_active_mds, |
---|
161 | | -#ifdef CONFIG_CEPH_FS_POSIX_ACL |
---|
162 | 158 | Opt_acl, |
---|
163 | | -#endif |
---|
164 | | - Opt_noacl, |
---|
165 | 159 | Opt_quotadf, |
---|
166 | | - Opt_noquotadf, |
---|
| 160 | + Opt_copyfrom, |
---|
| 161 | + Opt_wsync, |
---|
167 | 162 | }; |
---|
168 | 163 | |
---|
169 | | -static match_table_t fsopt_tokens = { |
---|
170 | | - {Opt_wsize, "wsize=%d"}, |
---|
171 | | - {Opt_rsize, "rsize=%d"}, |
---|
172 | | - {Opt_rasize, "rasize=%d"}, |
---|
173 | | - {Opt_caps_wanted_delay_min, "caps_wanted_delay_min=%d"}, |
---|
174 | | - {Opt_caps_wanted_delay_max, "caps_wanted_delay_max=%d"}, |
---|
175 | | - {Opt_readdir_max_entries, "readdir_max_entries=%d"}, |
---|
176 | | - {Opt_readdir_max_bytes, "readdir_max_bytes=%d"}, |
---|
177 | | - {Opt_congestion_kb, "write_congestion_kb=%d"}, |
---|
178 | | - /* int args above */ |
---|
179 | | - {Opt_snapdirname, "snapdirname=%s"}, |
---|
180 | | - {Opt_mds_namespace, "mds_namespace=%s"}, |
---|
181 | | - {Opt_fscache_uniq, "fsc=%s"}, |
---|
182 | | - /* string args above */ |
---|
183 | | - {Opt_dirstat, "dirstat"}, |
---|
184 | | - {Opt_nodirstat, "nodirstat"}, |
---|
185 | | - {Opt_rbytes, "rbytes"}, |
---|
186 | | - {Opt_norbytes, "norbytes"}, |
---|
187 | | - {Opt_asyncreaddir, "asyncreaddir"}, |
---|
188 | | - {Opt_noasyncreaddir, "noasyncreaddir"}, |
---|
189 | | - {Opt_dcache, "dcache"}, |
---|
190 | | - {Opt_nodcache, "nodcache"}, |
---|
191 | | - {Opt_ino32, "ino32"}, |
---|
192 | | - {Opt_noino32, "noino32"}, |
---|
193 | | - {Opt_fscache, "fsc"}, |
---|
194 | | - {Opt_nofscache, "nofsc"}, |
---|
195 | | - {Opt_poolperm, "poolperm"}, |
---|
196 | | - {Opt_nopoolperm, "nopoolperm"}, |
---|
197 | | - {Opt_require_active_mds, "require_active_mds"}, |
---|
198 | | - {Opt_norequire_active_mds, "norequire_active_mds"}, |
---|
199 | | -#ifdef CONFIG_CEPH_FS_POSIX_ACL |
---|
200 | | - {Opt_acl, "acl"}, |
---|
201 | | -#endif |
---|
202 | | - {Opt_noacl, "noacl"}, |
---|
203 | | - {Opt_quotadf, "quotadf"}, |
---|
204 | | - {Opt_noquotadf, "noquotadf"}, |
---|
205 | | - {-1, NULL} |
---|
| 164 | +enum ceph_recover_session_mode { |
---|
| 165 | + ceph_recover_session_no, |
---|
| 166 | + ceph_recover_session_clean |
---|
| 167 | +}; |
---|
| 168 | + |
---|
| 169 | +static const struct constant_table ceph_param_recover[] = { |
---|
| 170 | + { "no", ceph_recover_session_no }, |
---|
| 171 | + { "clean", ceph_recover_session_clean }, |
---|
| 172 | + {} |
---|
| 173 | +}; |
---|
| 174 | + |
---|
| 175 | +static const struct fs_parameter_spec ceph_mount_parameters[] = { |
---|
| 176 | + fsparam_flag_no ("acl", Opt_acl), |
---|
| 177 | + fsparam_flag_no ("asyncreaddir", Opt_asyncreaddir), |
---|
| 178 | + fsparam_s32 ("caps_max", Opt_caps_max), |
---|
| 179 | + fsparam_u32 ("caps_wanted_delay_max", Opt_caps_wanted_delay_max), |
---|
| 180 | + fsparam_u32 ("caps_wanted_delay_min", Opt_caps_wanted_delay_min), |
---|
| 181 | + fsparam_u32 ("write_congestion_kb", Opt_congestion_kb), |
---|
| 182 | + fsparam_flag_no ("copyfrom", Opt_copyfrom), |
---|
| 183 | + fsparam_flag_no ("dcache", Opt_dcache), |
---|
| 184 | + fsparam_flag_no ("dirstat", Opt_dirstat), |
---|
| 185 | + fsparam_flag_no ("fsc", Opt_fscache), // fsc|nofsc |
---|
| 186 | + fsparam_string ("fsc", Opt_fscache), // fsc=... |
---|
| 187 | + fsparam_flag_no ("ino32", Opt_ino32), |
---|
| 188 | + fsparam_string ("mds_namespace", Opt_mds_namespace), |
---|
| 189 | + fsparam_flag_no ("poolperm", Opt_poolperm), |
---|
| 190 | + fsparam_flag_no ("quotadf", Opt_quotadf), |
---|
| 191 | + fsparam_u32 ("rasize", Opt_rasize), |
---|
| 192 | + fsparam_flag_no ("rbytes", Opt_rbytes), |
---|
| 193 | + fsparam_u32 ("readdir_max_bytes", Opt_readdir_max_bytes), |
---|
| 194 | + fsparam_u32 ("readdir_max_entries", Opt_readdir_max_entries), |
---|
| 195 | + fsparam_enum ("recover_session", Opt_recover_session, ceph_param_recover), |
---|
| 196 | + fsparam_flag_no ("require_active_mds", Opt_require_active_mds), |
---|
| 197 | + fsparam_u32 ("rsize", Opt_rsize), |
---|
| 198 | + fsparam_string ("snapdirname", Opt_snapdirname), |
---|
| 199 | + fsparam_string ("source", Opt_source), |
---|
| 200 | + fsparam_u32 ("wsize", Opt_wsize), |
---|
| 201 | + fsparam_flag_no ("wsync", Opt_wsync), |
---|
| 202 | + {} |
---|
| 203 | +}; |
---|
| 204 | + |
---|
| 205 | +struct ceph_parse_opts_ctx { |
---|
| 206 | + struct ceph_options *copts; |
---|
| 207 | + struct ceph_mount_options *opts; |
---|
206 | 208 | }; |
---|
207 | 209 | |
---|
208 | 210 | /* |
---|
.. | .. |
---|
225 | 227 | path[j] = '\0'; |
---|
226 | 228 | } |
---|
227 | 229 | |
---|
228 | | -static int parse_fsopt_token(char *c, void *private) |
---|
| 230 | +/* |
---|
| 231 | + * Parse the source parameter. Distinguish the server list from the path. |
---|
| 232 | + * |
---|
| 233 | + * The source will look like: |
---|
| 234 | + * <server_spec>[,<server_spec>...]:[<path>] |
---|
| 235 | + * where |
---|
| 236 | + * <server_spec> is <ip>[:<port>] |
---|
| 237 | + * <path> is optional, but if present must begin with '/' |
---|
| 238 | + */ |
---|
| 239 | +static int ceph_parse_source(struct fs_parameter *param, struct fs_context *fc) |
---|
229 | 240 | { |
---|
230 | | - struct ceph_mount_options *fsopt = private; |
---|
231 | | - substring_t argstr[MAX_OPT_ARGS]; |
---|
232 | | - int token, intval, ret; |
---|
| 241 | + struct ceph_parse_opts_ctx *pctx = fc->fs_private; |
---|
| 242 | + struct ceph_mount_options *fsopt = pctx->opts; |
---|
| 243 | + char *dev_name = param->string, *dev_name_end; |
---|
| 244 | + int ret; |
---|
233 | 245 | |
---|
234 | | - token = match_token((char *)c, fsopt_tokens, argstr); |
---|
235 | | - if (token < 0) |
---|
236 | | - return -EINVAL; |
---|
| 246 | + dout("%s '%s'\n", __func__, dev_name); |
---|
| 247 | + if (!dev_name || !*dev_name) |
---|
| 248 | + return invalfc(fc, "Empty source"); |
---|
237 | 249 | |
---|
238 | | - if (token < Opt_last_int) { |
---|
239 | | - ret = match_int(&argstr[0], &intval); |
---|
240 | | - if (ret < 0) { |
---|
241 | | - pr_err("bad option arg (not int) at '%s'\n", c); |
---|
242 | | - return ret; |
---|
243 | | - } |
---|
244 | | - dout("got int token %d val %d\n", token, intval); |
---|
245 | | - } else if (token > Opt_last_int && token < Opt_last_string) { |
---|
246 | | - dout("got string token %d val %s\n", token, |
---|
247 | | - argstr[0].from); |
---|
| 250 | + dev_name_end = strchr(dev_name, '/'); |
---|
| 251 | + if (dev_name_end) { |
---|
| 252 | + /* |
---|
| 253 | + * The server_path will include the whole chars from userland |
---|
| 254 | + * including the leading '/'. |
---|
| 255 | + */ |
---|
| 256 | + kfree(fsopt->server_path); |
---|
| 257 | + fsopt->server_path = kstrdup(dev_name_end, GFP_KERNEL); |
---|
| 258 | + if (!fsopt->server_path) |
---|
| 259 | + return -ENOMEM; |
---|
| 260 | + |
---|
| 261 | + canonicalize_path(fsopt->server_path); |
---|
248 | 262 | } else { |
---|
249 | | - dout("got token %d\n", token); |
---|
| 263 | + dev_name_end = dev_name + strlen(dev_name); |
---|
250 | 264 | } |
---|
| 265 | + |
---|
| 266 | + dev_name_end--; /* back up to ':' separator */ |
---|
| 267 | + if (dev_name_end < dev_name || *dev_name_end != ':') |
---|
| 268 | + return invalfc(fc, "No path or : separator in source"); |
---|
| 269 | + |
---|
| 270 | + dout("device name '%.*s'\n", (int)(dev_name_end - dev_name), dev_name); |
---|
| 271 | + if (fsopt->server_path) |
---|
| 272 | + dout("server path '%s'\n", fsopt->server_path); |
---|
| 273 | + |
---|
| 274 | + ret = ceph_parse_mon_ips(param->string, dev_name_end - dev_name, |
---|
| 275 | + pctx->copts, fc->log.log); |
---|
| 276 | + if (ret) |
---|
| 277 | + return ret; |
---|
| 278 | + |
---|
| 279 | + fc->source = param->string; |
---|
| 280 | + param->string = NULL; |
---|
| 281 | + return 0; |
---|
| 282 | +} |
---|
| 283 | + |
---|
| 284 | +static int ceph_parse_mount_param(struct fs_context *fc, |
---|
| 285 | + struct fs_parameter *param) |
---|
| 286 | +{ |
---|
| 287 | + struct ceph_parse_opts_ctx *pctx = fc->fs_private; |
---|
| 288 | + struct ceph_mount_options *fsopt = pctx->opts; |
---|
| 289 | + struct fs_parse_result result; |
---|
| 290 | + unsigned int mode; |
---|
| 291 | + int token, ret; |
---|
| 292 | + |
---|
| 293 | + ret = ceph_parse_param(param, pctx->copts, fc->log.log); |
---|
| 294 | + if (ret != -ENOPARAM) |
---|
| 295 | + return ret; |
---|
| 296 | + |
---|
| 297 | + token = fs_parse(fc, ceph_mount_parameters, param, &result); |
---|
| 298 | + dout("%s fs_parse '%s' token %d\n", __func__, param->key, token); |
---|
| 299 | + if (token < 0) |
---|
| 300 | + return token; |
---|
251 | 301 | |
---|
252 | 302 | switch (token) { |
---|
253 | 303 | case Opt_snapdirname: |
---|
254 | 304 | kfree(fsopt->snapdir_name); |
---|
255 | | - fsopt->snapdir_name = kstrndup(argstr[0].from, |
---|
256 | | - argstr[0].to-argstr[0].from, |
---|
257 | | - GFP_KERNEL); |
---|
258 | | - if (!fsopt->snapdir_name) |
---|
259 | | - return -ENOMEM; |
---|
| 305 | + fsopt->snapdir_name = param->string; |
---|
| 306 | + param->string = NULL; |
---|
260 | 307 | break; |
---|
261 | 308 | case Opt_mds_namespace: |
---|
262 | 309 | kfree(fsopt->mds_namespace); |
---|
263 | | - fsopt->mds_namespace = kstrndup(argstr[0].from, |
---|
264 | | - argstr[0].to-argstr[0].from, |
---|
265 | | - GFP_KERNEL); |
---|
266 | | - if (!fsopt->mds_namespace) |
---|
267 | | - return -ENOMEM; |
---|
| 310 | + fsopt->mds_namespace = param->string; |
---|
| 311 | + param->string = NULL; |
---|
268 | 312 | break; |
---|
269 | | - case Opt_fscache_uniq: |
---|
270 | | -#ifdef CONFIG_CEPH_FSCACHE |
---|
271 | | - kfree(fsopt->fscache_uniq); |
---|
272 | | - fsopt->fscache_uniq = kstrndup(argstr[0].from, |
---|
273 | | - argstr[0].to-argstr[0].from, |
---|
274 | | - GFP_KERNEL); |
---|
275 | | - if (!fsopt->fscache_uniq) |
---|
276 | | - return -ENOMEM; |
---|
277 | | - fsopt->flags |= CEPH_MOUNT_OPT_FSCACHE; |
---|
| 313 | + case Opt_recover_session: |
---|
| 314 | + mode = result.uint_32; |
---|
| 315 | + if (mode == ceph_recover_session_no) |
---|
| 316 | + fsopt->flags &= ~CEPH_MOUNT_OPT_CLEANRECOVER; |
---|
| 317 | + else if (mode == ceph_recover_session_clean) |
---|
| 318 | + fsopt->flags |= CEPH_MOUNT_OPT_CLEANRECOVER; |
---|
| 319 | + else |
---|
| 320 | + BUG(); |
---|
278 | 321 | break; |
---|
279 | | -#else |
---|
280 | | - pr_err("fscache support is disabled\n"); |
---|
281 | | - return -EINVAL; |
---|
282 | | -#endif |
---|
| 322 | + case Opt_source: |
---|
| 323 | + if (fc->source) |
---|
| 324 | + return invalfc(fc, "Multiple sources specified"); |
---|
| 325 | + return ceph_parse_source(param, fc); |
---|
283 | 326 | case Opt_wsize: |
---|
284 | | - if (intval < (int)PAGE_SIZE || intval > CEPH_MAX_WRITE_SIZE) |
---|
285 | | - return -EINVAL; |
---|
286 | | - fsopt->wsize = ALIGN(intval, PAGE_SIZE); |
---|
| 327 | + if (result.uint_32 < PAGE_SIZE || |
---|
| 328 | + result.uint_32 > CEPH_MAX_WRITE_SIZE) |
---|
| 329 | + goto out_of_range; |
---|
| 330 | + fsopt->wsize = ALIGN(result.uint_32, PAGE_SIZE); |
---|
287 | 331 | break; |
---|
288 | 332 | case Opt_rsize: |
---|
289 | | - if (intval < (int)PAGE_SIZE || intval > CEPH_MAX_READ_SIZE) |
---|
290 | | - return -EINVAL; |
---|
291 | | - fsopt->rsize = ALIGN(intval, PAGE_SIZE); |
---|
| 333 | + if (result.uint_32 < PAGE_SIZE || |
---|
| 334 | + result.uint_32 > CEPH_MAX_READ_SIZE) |
---|
| 335 | + goto out_of_range; |
---|
| 336 | + fsopt->rsize = ALIGN(result.uint_32, PAGE_SIZE); |
---|
292 | 337 | break; |
---|
293 | 338 | case Opt_rasize: |
---|
294 | | - if (intval < 0) |
---|
295 | | - return -EINVAL; |
---|
296 | | - fsopt->rasize = ALIGN(intval, PAGE_SIZE); |
---|
| 339 | + fsopt->rasize = ALIGN(result.uint_32, PAGE_SIZE); |
---|
297 | 340 | break; |
---|
298 | 341 | case Opt_caps_wanted_delay_min: |
---|
299 | | - if (intval < 1) |
---|
300 | | - return -EINVAL; |
---|
301 | | - fsopt->caps_wanted_delay_min = intval; |
---|
| 342 | + if (result.uint_32 < 1) |
---|
| 343 | + goto out_of_range; |
---|
| 344 | + fsopt->caps_wanted_delay_min = result.uint_32; |
---|
302 | 345 | break; |
---|
303 | 346 | case Opt_caps_wanted_delay_max: |
---|
304 | | - if (intval < 1) |
---|
305 | | - return -EINVAL; |
---|
306 | | - fsopt->caps_wanted_delay_max = intval; |
---|
| 347 | + if (result.uint_32 < 1) |
---|
| 348 | + goto out_of_range; |
---|
| 349 | + fsopt->caps_wanted_delay_max = result.uint_32; |
---|
| 350 | + break; |
---|
| 351 | + case Opt_caps_max: |
---|
| 352 | + if (result.int_32 < 0) |
---|
| 353 | + goto out_of_range; |
---|
| 354 | + fsopt->caps_max = result.int_32; |
---|
307 | 355 | break; |
---|
308 | 356 | case Opt_readdir_max_entries: |
---|
309 | | - if (intval < 1) |
---|
310 | | - return -EINVAL; |
---|
311 | | - fsopt->max_readdir = intval; |
---|
| 357 | + if (result.uint_32 < 1) |
---|
| 358 | + goto out_of_range; |
---|
| 359 | + fsopt->max_readdir = result.uint_32; |
---|
312 | 360 | break; |
---|
313 | 361 | case Opt_readdir_max_bytes: |
---|
314 | | - if (intval < (int)PAGE_SIZE && intval != 0) |
---|
315 | | - return -EINVAL; |
---|
316 | | - fsopt->max_readdir_bytes = intval; |
---|
| 362 | + if (result.uint_32 < PAGE_SIZE && result.uint_32 != 0) |
---|
| 363 | + goto out_of_range; |
---|
| 364 | + fsopt->max_readdir_bytes = result.uint_32; |
---|
317 | 365 | break; |
---|
318 | 366 | case Opt_congestion_kb: |
---|
319 | | - if (intval < 1024) /* at least 1M */ |
---|
320 | | - return -EINVAL; |
---|
321 | | - fsopt->congestion_kb = intval; |
---|
| 367 | + if (result.uint_32 < 1024) /* at least 1M */ |
---|
| 368 | + goto out_of_range; |
---|
| 369 | + fsopt->congestion_kb = result.uint_32; |
---|
322 | 370 | break; |
---|
323 | 371 | case Opt_dirstat: |
---|
324 | | - fsopt->flags |= CEPH_MOUNT_OPT_DIRSTAT; |
---|
325 | | - break; |
---|
326 | | - case Opt_nodirstat: |
---|
327 | | - fsopt->flags &= ~CEPH_MOUNT_OPT_DIRSTAT; |
---|
| 372 | + if (!result.negated) |
---|
| 373 | + fsopt->flags |= CEPH_MOUNT_OPT_DIRSTAT; |
---|
| 374 | + else |
---|
| 375 | + fsopt->flags &= ~CEPH_MOUNT_OPT_DIRSTAT; |
---|
328 | 376 | break; |
---|
329 | 377 | case Opt_rbytes: |
---|
330 | | - fsopt->flags |= CEPH_MOUNT_OPT_RBYTES; |
---|
331 | | - break; |
---|
332 | | - case Opt_norbytes: |
---|
333 | | - fsopt->flags &= ~CEPH_MOUNT_OPT_RBYTES; |
---|
| 378 | + if (!result.negated) |
---|
| 379 | + fsopt->flags |= CEPH_MOUNT_OPT_RBYTES; |
---|
| 380 | + else |
---|
| 381 | + fsopt->flags &= ~CEPH_MOUNT_OPT_RBYTES; |
---|
334 | 382 | break; |
---|
335 | 383 | case Opt_asyncreaddir: |
---|
336 | | - fsopt->flags &= ~CEPH_MOUNT_OPT_NOASYNCREADDIR; |
---|
337 | | - break; |
---|
338 | | - case Opt_noasyncreaddir: |
---|
339 | | - fsopt->flags |= CEPH_MOUNT_OPT_NOASYNCREADDIR; |
---|
| 384 | + if (!result.negated) |
---|
| 385 | + fsopt->flags &= ~CEPH_MOUNT_OPT_NOASYNCREADDIR; |
---|
| 386 | + else |
---|
| 387 | + fsopt->flags |= CEPH_MOUNT_OPT_NOASYNCREADDIR; |
---|
340 | 388 | break; |
---|
341 | 389 | case Opt_dcache: |
---|
342 | | - fsopt->flags |= CEPH_MOUNT_OPT_DCACHE; |
---|
343 | | - break; |
---|
344 | | - case Opt_nodcache: |
---|
345 | | - fsopt->flags &= ~CEPH_MOUNT_OPT_DCACHE; |
---|
| 390 | + if (!result.negated) |
---|
| 391 | + fsopt->flags |= CEPH_MOUNT_OPT_DCACHE; |
---|
| 392 | + else |
---|
| 393 | + fsopt->flags &= ~CEPH_MOUNT_OPT_DCACHE; |
---|
346 | 394 | break; |
---|
347 | 395 | case Opt_ino32: |
---|
348 | | - fsopt->flags |= CEPH_MOUNT_OPT_INO32; |
---|
| 396 | + if (!result.negated) |
---|
| 397 | + fsopt->flags |= CEPH_MOUNT_OPT_INO32; |
---|
| 398 | + else |
---|
| 399 | + fsopt->flags &= ~CEPH_MOUNT_OPT_INO32; |
---|
349 | 400 | break; |
---|
350 | | - case Opt_noino32: |
---|
351 | | - fsopt->flags &= ~CEPH_MOUNT_OPT_INO32; |
---|
352 | | - break; |
---|
| 401 | + |
---|
353 | 402 | case Opt_fscache: |
---|
354 | 403 | #ifdef CONFIG_CEPH_FSCACHE |
---|
355 | | - fsopt->flags |= CEPH_MOUNT_OPT_FSCACHE; |
---|
356 | 404 | kfree(fsopt->fscache_uniq); |
---|
357 | 405 | fsopt->fscache_uniq = NULL; |
---|
| 406 | + if (result.negated) { |
---|
| 407 | + fsopt->flags &= ~CEPH_MOUNT_OPT_FSCACHE; |
---|
| 408 | + } else { |
---|
| 409 | + fsopt->flags |= CEPH_MOUNT_OPT_FSCACHE; |
---|
| 410 | + fsopt->fscache_uniq = param->string; |
---|
| 411 | + param->string = NULL; |
---|
| 412 | + } |
---|
358 | 413 | break; |
---|
359 | 414 | #else |
---|
360 | | - pr_err("fscache support is disabled\n"); |
---|
361 | | - return -EINVAL; |
---|
| 415 | + return invalfc(fc, "fscache support is disabled"); |
---|
362 | 416 | #endif |
---|
363 | | - case Opt_nofscache: |
---|
364 | | - fsopt->flags &= ~CEPH_MOUNT_OPT_FSCACHE; |
---|
365 | | - kfree(fsopt->fscache_uniq); |
---|
366 | | - fsopt->fscache_uniq = NULL; |
---|
367 | | - break; |
---|
368 | 417 | case Opt_poolperm: |
---|
369 | | - fsopt->flags &= ~CEPH_MOUNT_OPT_NOPOOLPERM; |
---|
370 | | - break; |
---|
371 | | - case Opt_nopoolperm: |
---|
372 | | - fsopt->flags |= CEPH_MOUNT_OPT_NOPOOLPERM; |
---|
| 418 | + if (!result.negated) |
---|
| 419 | + fsopt->flags &= ~CEPH_MOUNT_OPT_NOPOOLPERM; |
---|
| 420 | + else |
---|
| 421 | + fsopt->flags |= CEPH_MOUNT_OPT_NOPOOLPERM; |
---|
373 | 422 | break; |
---|
374 | 423 | case Opt_require_active_mds: |
---|
375 | | - fsopt->flags &= ~CEPH_MOUNT_OPT_MOUNTWAIT; |
---|
376 | | - break; |
---|
377 | | - case Opt_norequire_active_mds: |
---|
378 | | - fsopt->flags |= CEPH_MOUNT_OPT_MOUNTWAIT; |
---|
| 424 | + if (!result.negated) |
---|
| 425 | + fsopt->flags &= ~CEPH_MOUNT_OPT_MOUNTWAIT; |
---|
| 426 | + else |
---|
| 427 | + fsopt->flags |= CEPH_MOUNT_OPT_MOUNTWAIT; |
---|
379 | 428 | break; |
---|
380 | 429 | case Opt_quotadf: |
---|
381 | | - fsopt->flags &= ~CEPH_MOUNT_OPT_NOQUOTADF; |
---|
| 430 | + if (!result.negated) |
---|
| 431 | + fsopt->flags &= ~CEPH_MOUNT_OPT_NOQUOTADF; |
---|
| 432 | + else |
---|
| 433 | + fsopt->flags |= CEPH_MOUNT_OPT_NOQUOTADF; |
---|
382 | 434 | break; |
---|
383 | | - case Opt_noquotadf: |
---|
384 | | - fsopt->flags |= CEPH_MOUNT_OPT_NOQUOTADF; |
---|
| 435 | + case Opt_copyfrom: |
---|
| 436 | + if (!result.negated) |
---|
| 437 | + fsopt->flags &= ~CEPH_MOUNT_OPT_NOCOPYFROM; |
---|
| 438 | + else |
---|
| 439 | + fsopt->flags |= CEPH_MOUNT_OPT_NOCOPYFROM; |
---|
385 | 440 | break; |
---|
386 | | -#ifdef CONFIG_CEPH_FS_POSIX_ACL |
---|
387 | 441 | case Opt_acl: |
---|
388 | | - fsopt->sb_flags |= SB_POSIXACL; |
---|
389 | | - break; |
---|
| 442 | + if (!result.negated) { |
---|
| 443 | +#ifdef CONFIG_CEPH_FS_POSIX_ACL |
---|
| 444 | + fc->sb_flags |= SB_POSIXACL; |
---|
| 445 | +#else |
---|
| 446 | + return invalfc(fc, "POSIX ACL support is disabled"); |
---|
390 | 447 | #endif |
---|
391 | | - case Opt_noacl: |
---|
392 | | - fsopt->sb_flags &= ~SB_POSIXACL; |
---|
| 448 | + } else { |
---|
| 449 | + fc->sb_flags &= ~SB_POSIXACL; |
---|
| 450 | + } |
---|
| 451 | + break; |
---|
| 452 | + case Opt_wsync: |
---|
| 453 | + if (!result.negated) |
---|
| 454 | + fsopt->flags &= ~CEPH_MOUNT_OPT_ASYNC_DIROPS; |
---|
| 455 | + else |
---|
| 456 | + fsopt->flags |= CEPH_MOUNT_OPT_ASYNC_DIROPS; |
---|
393 | 457 | break; |
---|
394 | 458 | default: |
---|
395 | | - BUG_ON(token); |
---|
| 459 | + BUG(); |
---|
396 | 460 | } |
---|
397 | 461 | return 0; |
---|
| 462 | + |
---|
| 463 | +out_of_range: |
---|
| 464 | + return invalfc(fc, "%s out of range", param->key); |
---|
398 | 465 | } |
---|
399 | 466 | |
---|
400 | 467 | static void destroy_mount_options(struct ceph_mount_options *args) |
---|
401 | 468 | { |
---|
402 | 469 | dout("destroy_mount_options %p\n", args); |
---|
| 470 | + if (!args) |
---|
| 471 | + return; |
---|
| 472 | + |
---|
403 | 473 | kfree(args->snapdir_name); |
---|
404 | 474 | kfree(args->mds_namespace); |
---|
405 | 475 | kfree(args->server_path); |
---|
.. | .. |
---|
450 | 520 | return ceph_compare_options(new_opt, fsc->client); |
---|
451 | 521 | } |
---|
452 | 522 | |
---|
453 | | -static int parse_mount_options(struct ceph_mount_options **pfsopt, |
---|
454 | | - struct ceph_options **popt, |
---|
455 | | - int flags, char *options, |
---|
456 | | - const char *dev_name) |
---|
457 | | -{ |
---|
458 | | - struct ceph_mount_options *fsopt; |
---|
459 | | - const char *dev_name_end; |
---|
460 | | - int err; |
---|
461 | | - |
---|
462 | | - if (!dev_name || !*dev_name) |
---|
463 | | - return -EINVAL; |
---|
464 | | - |
---|
465 | | - fsopt = kzalloc(sizeof(*fsopt), GFP_KERNEL); |
---|
466 | | - if (!fsopt) |
---|
467 | | - return -ENOMEM; |
---|
468 | | - |
---|
469 | | - dout("parse_mount_options %p, dev_name '%s'\n", fsopt, dev_name); |
---|
470 | | - |
---|
471 | | - fsopt->sb_flags = flags; |
---|
472 | | - fsopt->flags = CEPH_MOUNT_OPT_DEFAULT; |
---|
473 | | - |
---|
474 | | - fsopt->wsize = CEPH_MAX_WRITE_SIZE; |
---|
475 | | - fsopt->rsize = CEPH_MAX_READ_SIZE; |
---|
476 | | - fsopt->rasize = CEPH_RASIZE_DEFAULT; |
---|
477 | | - fsopt->snapdir_name = kstrdup(CEPH_SNAPDIRNAME_DEFAULT, GFP_KERNEL); |
---|
478 | | - if (!fsopt->snapdir_name) { |
---|
479 | | - err = -ENOMEM; |
---|
480 | | - goto out; |
---|
481 | | - } |
---|
482 | | - |
---|
483 | | - fsopt->caps_wanted_delay_min = CEPH_CAPS_WANTED_DELAY_MIN_DEFAULT; |
---|
484 | | - fsopt->caps_wanted_delay_max = CEPH_CAPS_WANTED_DELAY_MAX_DEFAULT; |
---|
485 | | - fsopt->max_readdir = CEPH_MAX_READDIR_DEFAULT; |
---|
486 | | - fsopt->max_readdir_bytes = CEPH_MAX_READDIR_BYTES_DEFAULT; |
---|
487 | | - fsopt->congestion_kb = default_congestion_kb(); |
---|
488 | | - |
---|
489 | | - /* |
---|
490 | | - * Distinguish the server list from the path in "dev_name". |
---|
491 | | - * Internally we do not include the leading '/' in the path. |
---|
492 | | - * |
---|
493 | | - * "dev_name" will look like: |
---|
494 | | - * <server_spec>[,<server_spec>...]:[<path>] |
---|
495 | | - * where |
---|
496 | | - * <server_spec> is <ip>[:<port>] |
---|
497 | | - * <path> is optional, but if present must begin with '/' |
---|
498 | | - */ |
---|
499 | | - dev_name_end = strchr(dev_name, '/'); |
---|
500 | | - if (dev_name_end) { |
---|
501 | | - /* |
---|
502 | | - * The server_path will include the whole chars from userland |
---|
503 | | - * including the leading '/'. |
---|
504 | | - */ |
---|
505 | | - fsopt->server_path = kstrdup(dev_name_end, GFP_KERNEL); |
---|
506 | | - if (!fsopt->server_path) { |
---|
507 | | - err = -ENOMEM; |
---|
508 | | - goto out; |
---|
509 | | - } |
---|
510 | | - |
---|
511 | | - canonicalize_path(fsopt->server_path); |
---|
512 | | - } else { |
---|
513 | | - dev_name_end = dev_name + strlen(dev_name); |
---|
514 | | - } |
---|
515 | | - err = -EINVAL; |
---|
516 | | - dev_name_end--; /* back up to ':' separator */ |
---|
517 | | - if (dev_name_end < dev_name || *dev_name_end != ':') { |
---|
518 | | - pr_err("device name is missing path (no : separator in %s)\n", |
---|
519 | | - dev_name); |
---|
520 | | - goto out; |
---|
521 | | - } |
---|
522 | | - dout("device name '%.*s'\n", (int)(dev_name_end - dev_name), dev_name); |
---|
523 | | - if (fsopt->server_path) |
---|
524 | | - dout("server path '%s'\n", fsopt->server_path); |
---|
525 | | - |
---|
526 | | - *popt = ceph_parse_options(options, dev_name, dev_name_end, |
---|
527 | | - parse_fsopt_token, (void *)fsopt); |
---|
528 | | - if (IS_ERR(*popt)) { |
---|
529 | | - err = PTR_ERR(*popt); |
---|
530 | | - goto out; |
---|
531 | | - } |
---|
532 | | - |
---|
533 | | - /* success */ |
---|
534 | | - *pfsopt = fsopt; |
---|
535 | | - return 0; |
---|
536 | | - |
---|
537 | | -out: |
---|
538 | | - destroy_mount_options(fsopt); |
---|
539 | | - return err; |
---|
540 | | -} |
---|
541 | | - |
---|
542 | 523 | /** |
---|
543 | 524 | * ceph_show_options - Show mount options in /proc/mounts |
---|
544 | 525 | * @m: seq_file to write to |
---|
.. | .. |
---|
555 | 536 | seq_putc(m, ','); |
---|
556 | 537 | pos = m->count; |
---|
557 | 538 | |
---|
558 | | - ret = ceph_print_client_options(m, fsc->client); |
---|
| 539 | + ret = ceph_print_client_options(m, fsc->client, false); |
---|
559 | 540 | if (ret) |
---|
560 | 541 | return ret; |
---|
561 | 542 | |
---|
.. | .. |
---|
582 | 563 | seq_puts(m, ",noquotadf"); |
---|
583 | 564 | |
---|
584 | 565 | #ifdef CONFIG_CEPH_FS_POSIX_ACL |
---|
585 | | - if (fsopt->sb_flags & SB_POSIXACL) |
---|
| 566 | + if (root->d_sb->s_flags & SB_POSIXACL) |
---|
586 | 567 | seq_puts(m, ",acl"); |
---|
587 | 568 | else |
---|
588 | 569 | seq_puts(m, ",noacl"); |
---|
589 | 570 | #endif |
---|
590 | 571 | |
---|
| 572 | + if ((fsopt->flags & CEPH_MOUNT_OPT_NOCOPYFROM) == 0) |
---|
| 573 | + seq_puts(m, ",copyfrom"); |
---|
| 574 | + |
---|
591 | 575 | if (fsopt->mds_namespace) |
---|
592 | 576 | seq_show_option(m, "mds_namespace", fsopt->mds_namespace); |
---|
| 577 | + |
---|
| 578 | + if (fsopt->flags & CEPH_MOUNT_OPT_CLEANRECOVER) |
---|
| 579 | + seq_show_option(m, "recover_session", "clean"); |
---|
| 580 | + |
---|
| 581 | + if (fsopt->flags & CEPH_MOUNT_OPT_ASYNC_DIROPS) |
---|
| 582 | + seq_puts(m, ",nowsync"); |
---|
| 583 | + |
---|
593 | 584 | if (fsopt->wsize != CEPH_MAX_WRITE_SIZE) |
---|
594 | | - seq_printf(m, ",wsize=%d", fsopt->wsize); |
---|
| 585 | + seq_printf(m, ",wsize=%u", fsopt->wsize); |
---|
595 | 586 | if (fsopt->rsize != CEPH_MAX_READ_SIZE) |
---|
596 | | - seq_printf(m, ",rsize=%d", fsopt->rsize); |
---|
| 587 | + seq_printf(m, ",rsize=%u", fsopt->rsize); |
---|
597 | 588 | if (fsopt->rasize != CEPH_RASIZE_DEFAULT) |
---|
598 | | - seq_printf(m, ",rasize=%d", fsopt->rasize); |
---|
| 589 | + seq_printf(m, ",rasize=%u", fsopt->rasize); |
---|
599 | 590 | if (fsopt->congestion_kb != default_congestion_kb()) |
---|
600 | | - seq_printf(m, ",write_congestion_kb=%d", fsopt->congestion_kb); |
---|
| 591 | + seq_printf(m, ",write_congestion_kb=%u", fsopt->congestion_kb); |
---|
| 592 | + if (fsopt->caps_max) |
---|
| 593 | + seq_printf(m, ",caps_max=%d", fsopt->caps_max); |
---|
601 | 594 | if (fsopt->caps_wanted_delay_min != CEPH_CAPS_WANTED_DELAY_MIN_DEFAULT) |
---|
602 | | - seq_printf(m, ",caps_wanted_delay_min=%d", |
---|
| 595 | + seq_printf(m, ",caps_wanted_delay_min=%u", |
---|
603 | 596 | fsopt->caps_wanted_delay_min); |
---|
604 | 597 | if (fsopt->caps_wanted_delay_max != CEPH_CAPS_WANTED_DELAY_MAX_DEFAULT) |
---|
605 | | - seq_printf(m, ",caps_wanted_delay_max=%d", |
---|
| 598 | + seq_printf(m, ",caps_wanted_delay_max=%u", |
---|
606 | 599 | fsopt->caps_wanted_delay_max); |
---|
607 | 600 | if (fsopt->max_readdir != CEPH_MAX_READDIR_DEFAULT) |
---|
608 | | - seq_printf(m, ",readdir_max_entries=%d", fsopt->max_readdir); |
---|
| 601 | + seq_printf(m, ",readdir_max_entries=%u", fsopt->max_readdir); |
---|
609 | 602 | if (fsopt->max_readdir_bytes != CEPH_MAX_READDIR_BYTES_DEFAULT) |
---|
610 | | - seq_printf(m, ",readdir_max_bytes=%d", fsopt->max_readdir_bytes); |
---|
| 603 | + seq_printf(m, ",readdir_max_bytes=%u", fsopt->max_readdir_bytes); |
---|
611 | 604 | if (strcmp(fsopt->snapdir_name, CEPH_SNAPDIRNAME_DEFAULT)) |
---|
612 | 605 | seq_show_option(m, "snapdirname", fsopt->snapdir_name); |
---|
613 | 606 | |
---|
.. | .. |
---|
644 | 637 | struct ceph_options *opt) |
---|
645 | 638 | { |
---|
646 | 639 | struct ceph_fs_client *fsc; |
---|
647 | | - int page_count; |
---|
648 | | - size_t size; |
---|
649 | 640 | int err; |
---|
650 | 641 | |
---|
651 | 642 | fsc = kzalloc(sizeof(*fsc), GFP_KERNEL); |
---|
.. | .. |
---|
662 | 653 | opt = NULL; /* fsc->client now owns this */ |
---|
663 | 654 | |
---|
664 | 655 | fsc->client->extra_mon_dispatch = extra_mon_dispatch; |
---|
665 | | - fsc->client->osdc.abort_on_full = true; |
---|
| 656 | + ceph_set_opt(fsc->client, ABORT_ON_FULL); |
---|
666 | 657 | |
---|
667 | 658 | if (!fsopt->mds_namespace) { |
---|
668 | 659 | ceph_monc_want_map(&fsc->client->monc, CEPH_SUB_MDSMAP, |
---|
.. | .. |
---|
676 | 667 | |
---|
677 | 668 | fsc->sb = NULL; |
---|
678 | 669 | fsc->mount_state = CEPH_MOUNT_MOUNTING; |
---|
| 670 | + fsc->filp_gen = 1; |
---|
| 671 | + fsc->have_copy_from2 = true; |
---|
679 | 672 | |
---|
680 | 673 | atomic_long_set(&fsc->writeback_count, 0); |
---|
681 | 674 | |
---|
.. | .. |
---|
684 | 677 | * The number of concurrent works can be high but they don't need |
---|
685 | 678 | * to be processed in parallel, limit concurrency. |
---|
686 | 679 | */ |
---|
687 | | - fsc->wb_wq = alloc_workqueue("ceph-writeback", 0, 1); |
---|
688 | | - if (!fsc->wb_wq) |
---|
| 680 | + fsc->inode_wq = alloc_workqueue("ceph-inode", WQ_UNBOUND, 0); |
---|
| 681 | + if (!fsc->inode_wq) |
---|
689 | 682 | goto fail_client; |
---|
690 | | - fsc->pg_inv_wq = alloc_workqueue("ceph-pg-invalid", 0, 1); |
---|
691 | | - if (!fsc->pg_inv_wq) |
---|
692 | | - goto fail_wb_wq; |
---|
693 | | - fsc->trunc_wq = alloc_workqueue("ceph-trunc", 0, 1); |
---|
694 | | - if (!fsc->trunc_wq) |
---|
695 | | - goto fail_pg_inv_wq; |
---|
| 683 | + fsc->cap_wq = alloc_workqueue("ceph-cap", 0, 1); |
---|
| 684 | + if (!fsc->cap_wq) |
---|
| 685 | + goto fail_inode_wq; |
---|
696 | 686 | |
---|
697 | | - /* set up mempools */ |
---|
698 | | - err = -ENOMEM; |
---|
699 | | - page_count = fsc->mount_options->wsize >> PAGE_SHIFT; |
---|
700 | | - size = sizeof (struct page *) * (page_count ? page_count : 1); |
---|
701 | | - fsc->wb_pagevec_pool = mempool_create_kmalloc_pool(10, size); |
---|
702 | | - if (!fsc->wb_pagevec_pool) |
---|
703 | | - goto fail_trunc_wq; |
---|
704 | | - |
---|
705 | | - /* caps */ |
---|
706 | | - fsc->min_caps = fsopt->max_readdir; |
---|
| 687 | + spin_lock(&ceph_fsc_lock); |
---|
| 688 | + list_add_tail(&fsc->metric_wakeup, &ceph_fsc_list); |
---|
| 689 | + spin_unlock(&ceph_fsc_lock); |
---|
707 | 690 | |
---|
708 | 691 | return fsc; |
---|
709 | 692 | |
---|
710 | | -fail_trunc_wq: |
---|
711 | | - destroy_workqueue(fsc->trunc_wq); |
---|
712 | | -fail_pg_inv_wq: |
---|
713 | | - destroy_workqueue(fsc->pg_inv_wq); |
---|
714 | | -fail_wb_wq: |
---|
715 | | - destroy_workqueue(fsc->wb_wq); |
---|
| 693 | +fail_inode_wq: |
---|
| 694 | + destroy_workqueue(fsc->inode_wq); |
---|
716 | 695 | fail_client: |
---|
717 | 696 | ceph_destroy_client(fsc->client); |
---|
718 | 697 | fail: |
---|
.. | .. |
---|
725 | 704 | |
---|
726 | 705 | static void flush_fs_workqueues(struct ceph_fs_client *fsc) |
---|
727 | 706 | { |
---|
728 | | - flush_workqueue(fsc->wb_wq); |
---|
729 | | - flush_workqueue(fsc->pg_inv_wq); |
---|
730 | | - flush_workqueue(fsc->trunc_wq); |
---|
| 707 | + flush_workqueue(fsc->inode_wq); |
---|
| 708 | + flush_workqueue(fsc->cap_wq); |
---|
731 | 709 | } |
---|
732 | 710 | |
---|
733 | 711 | static void destroy_fs_client(struct ceph_fs_client *fsc) |
---|
734 | 712 | { |
---|
735 | 713 | dout("destroy_fs_client %p\n", fsc); |
---|
736 | 714 | |
---|
737 | | - destroy_workqueue(fsc->wb_wq); |
---|
738 | | - destroy_workqueue(fsc->pg_inv_wq); |
---|
739 | | - destroy_workqueue(fsc->trunc_wq); |
---|
| 715 | + spin_lock(&ceph_fsc_lock); |
---|
| 716 | + list_del(&fsc->metric_wakeup); |
---|
| 717 | + spin_unlock(&ceph_fsc_lock); |
---|
740 | 718 | |
---|
741 | | - mempool_destroy(fsc->wb_pagevec_pool); |
---|
| 719 | + ceph_mdsc_destroy(fsc); |
---|
| 720 | + destroy_workqueue(fsc->inode_wq); |
---|
| 721 | + destroy_workqueue(fsc->cap_wq); |
---|
742 | 722 | |
---|
743 | 723 | destroy_mount_options(fsc->mount_options); |
---|
744 | 724 | |
---|
.. | .. |
---|
757 | 737 | struct kmem_cache *ceph_dentry_cachep; |
---|
758 | 738 | struct kmem_cache *ceph_file_cachep; |
---|
759 | 739 | struct kmem_cache *ceph_dir_file_cachep; |
---|
| 740 | +struct kmem_cache *ceph_mds_request_cachep; |
---|
| 741 | +mempool_t *ceph_wb_pagevec_pool; |
---|
760 | 742 | |
---|
761 | 743 | static void ceph_inode_init_once(void *foo) |
---|
762 | 744 | { |
---|
.. | .. |
---|
797 | 779 | if (!ceph_dir_file_cachep) |
---|
798 | 780 | goto bad_dir_file; |
---|
799 | 781 | |
---|
| 782 | + ceph_mds_request_cachep = KMEM_CACHE(ceph_mds_request, SLAB_MEM_SPREAD); |
---|
| 783 | + if (!ceph_mds_request_cachep) |
---|
| 784 | + goto bad_mds_req; |
---|
| 785 | + |
---|
| 786 | + ceph_wb_pagevec_pool = mempool_create_kmalloc_pool(10, CEPH_MAX_WRITE_SIZE >> PAGE_SHIFT); |
---|
| 787 | + if (!ceph_wb_pagevec_pool) |
---|
| 788 | + goto bad_pagevec_pool; |
---|
| 789 | + |
---|
800 | 790 | error = ceph_fscache_register(); |
---|
801 | 791 | if (error) |
---|
802 | 792 | goto bad_fscache; |
---|
.. | .. |
---|
804 | 794 | return 0; |
---|
805 | 795 | |
---|
806 | 796 | bad_fscache: |
---|
| 797 | + kmem_cache_destroy(ceph_mds_request_cachep); |
---|
| 798 | +bad_pagevec_pool: |
---|
| 799 | + mempool_destroy(ceph_wb_pagevec_pool); |
---|
| 800 | +bad_mds_req: |
---|
807 | 801 | kmem_cache_destroy(ceph_dir_file_cachep); |
---|
808 | 802 | bad_dir_file: |
---|
809 | 803 | kmem_cache_destroy(ceph_file_cachep); |
---|
.. | .. |
---|
832 | 826 | kmem_cache_destroy(ceph_dentry_cachep); |
---|
833 | 827 | kmem_cache_destroy(ceph_file_cachep); |
---|
834 | 828 | kmem_cache_destroy(ceph_dir_file_cachep); |
---|
| 829 | + kmem_cache_destroy(ceph_mds_request_cachep); |
---|
| 830 | + mempool_destroy(ceph_wb_pagevec_pool); |
---|
835 | 831 | |
---|
836 | 832 | ceph_fscache_unregister(); |
---|
837 | 833 | } |
---|
838 | 834 | |
---|
839 | 835 | /* |
---|
840 | | - * ceph_umount_begin - initiate forced umount. Tear down down the |
---|
| 836 | + * ceph_umount_begin - initiate forced umount. Tear down the |
---|
841 | 837 | * mount, skipping steps that may hang while waiting for server(s). |
---|
842 | 838 | */ |
---|
843 | 839 | static void ceph_umount_begin(struct super_block *sb) |
---|
.. | .. |
---|
850 | 846 | fsc->mount_state = CEPH_MOUNT_SHUTDOWN; |
---|
851 | 847 | ceph_osdc_abort_requests(&fsc->client->osdc, -EIO); |
---|
852 | 848 | ceph_mdsc_force_umount(fsc->mdsc); |
---|
853 | | - return; |
---|
854 | | -} |
---|
855 | | - |
---|
856 | | -static int ceph_remount(struct super_block *sb, int *flags, char *data) |
---|
857 | | -{ |
---|
858 | | - sync_filesystem(sb); |
---|
859 | | - return 0; |
---|
| 849 | + fsc->filp_gen++; // invalidate open files |
---|
860 | 850 | } |
---|
861 | 851 | |
---|
862 | 852 | static const struct super_operations ceph_super_ops = { |
---|
863 | 853 | .alloc_inode = ceph_alloc_inode, |
---|
864 | | - .destroy_inode = ceph_destroy_inode, |
---|
| 854 | + .free_inode = ceph_free_inode, |
---|
865 | 855 | .write_inode = ceph_write_inode, |
---|
866 | | - .drop_inode = ceph_drop_inode, |
---|
| 856 | + .drop_inode = generic_delete_inode, |
---|
867 | 857 | .evict_inode = ceph_evict_inode, |
---|
868 | 858 | .sync_fs = ceph_sync_fs, |
---|
869 | 859 | .put_super = ceph_put_super, |
---|
870 | | - .remount_fs = ceph_remount, |
---|
871 | 860 | .show_options = ceph_show_options, |
---|
872 | 861 | .statfs = ceph_statfs, |
---|
873 | 862 | .umount_begin = ceph_umount_begin, |
---|
.. | .. |
---|
925 | 914 | /* |
---|
926 | 915 | * mount: join the ceph cluster, and open root directory. |
---|
927 | 916 | */ |
---|
928 | | -static struct dentry *ceph_real_mount(struct ceph_fs_client *fsc) |
---|
| 917 | +static struct dentry *ceph_real_mount(struct ceph_fs_client *fsc, |
---|
| 918 | + struct fs_context *fc) |
---|
929 | 919 | { |
---|
930 | 920 | int err; |
---|
931 | 921 | unsigned long started = jiffies; /* note the start time */ |
---|
.. | .. |
---|
944 | 934 | |
---|
945 | 935 | /* setup fscache */ |
---|
946 | 936 | if (fsc->mount_options->flags & CEPH_MOUNT_OPT_FSCACHE) { |
---|
947 | | - err = ceph_fscache_register_fs(fsc); |
---|
| 937 | + err = ceph_fscache_register_fs(fsc, fc); |
---|
948 | 938 | if (err < 0) |
---|
949 | 939 | goto out; |
---|
950 | 940 | } |
---|
951 | 941 | |
---|
952 | 942 | dout("mount opening path '%s'\n", path); |
---|
953 | 943 | |
---|
954 | | - err = ceph_fs_debugfs_init(fsc); |
---|
955 | | - if (err < 0) |
---|
956 | | - goto out; |
---|
| 944 | + ceph_fs_debugfs_init(fsc); |
---|
957 | 945 | |
---|
958 | 946 | root = open_root_dentry(fsc, path, started); |
---|
959 | 947 | if (IS_ERR(root)) { |
---|
.. | .. |
---|
975 | 963 | return ERR_PTR(err); |
---|
976 | 964 | } |
---|
977 | 965 | |
---|
978 | | -static int ceph_set_super(struct super_block *s, void *data) |
---|
| 966 | +static int ceph_set_super(struct super_block *s, struct fs_context *fc) |
---|
979 | 967 | { |
---|
980 | | - struct ceph_fs_client *fsc = data; |
---|
| 968 | + struct ceph_fs_client *fsc = s->s_fs_info; |
---|
981 | 969 | int ret; |
---|
982 | 970 | |
---|
983 | | - dout("set_super %p data %p\n", s, data); |
---|
| 971 | + dout("set_super %p\n", s); |
---|
984 | 972 | |
---|
985 | | - s->s_flags = fsc->mount_options->sb_flags; |
---|
986 | 973 | s->s_maxbytes = MAX_LFS_FILESIZE; |
---|
987 | 974 | |
---|
988 | 975 | s->s_xattr = ceph_xattr_handlers; |
---|
989 | | - s->s_fs_info = fsc; |
---|
990 | 976 | fsc->sb = s; |
---|
991 | 977 | fsc->max_file_size = 1ULL << 40; /* temp value until we get mdsmap */ |
---|
992 | 978 | |
---|
.. | .. |
---|
994 | 980 | s->s_d_op = &ceph_dentry_ops; |
---|
995 | 981 | s->s_export_op = &ceph_export_ops; |
---|
996 | 982 | |
---|
997 | | - s->s_time_gran = 1000; /* 1000 ns == 1 us */ |
---|
| 983 | + s->s_time_gran = 1; |
---|
| 984 | + s->s_time_min = 0; |
---|
| 985 | + s->s_time_max = U32_MAX; |
---|
998 | 986 | |
---|
999 | | - ret = set_anon_super(s, NULL); /* what is that second arg for? */ |
---|
| 987 | + ret = set_anon_super_fc(s, fc); |
---|
1000 | 988 | if (ret != 0) |
---|
1001 | | - goto fail; |
---|
1002 | | - |
---|
1003 | | - return ret; |
---|
1004 | | - |
---|
1005 | | -fail: |
---|
1006 | | - s->s_fs_info = NULL; |
---|
1007 | | - fsc->sb = NULL; |
---|
| 989 | + fsc->sb = NULL; |
---|
1008 | 990 | return ret; |
---|
1009 | 991 | } |
---|
1010 | 992 | |
---|
1011 | 993 | /* |
---|
1012 | 994 | * share superblock if same fs AND options |
---|
1013 | 995 | */ |
---|
1014 | | -static int ceph_compare_super(struct super_block *sb, void *data) |
---|
| 996 | +static int ceph_compare_super(struct super_block *sb, struct fs_context *fc) |
---|
1015 | 997 | { |
---|
1016 | | - struct ceph_fs_client *new = data; |
---|
| 998 | + struct ceph_fs_client *new = fc->s_fs_info; |
---|
1017 | 999 | struct ceph_mount_options *fsopt = new->mount_options; |
---|
1018 | 1000 | struct ceph_options *opt = new->client->options; |
---|
1019 | | - struct ceph_fs_client *other = ceph_sb_to_client(sb); |
---|
| 1001 | + struct ceph_fs_client *fsc = ceph_sb_to_client(sb); |
---|
1020 | 1002 | |
---|
1021 | 1003 | dout("ceph_compare_super %p\n", sb); |
---|
1022 | 1004 | |
---|
1023 | | - if (compare_mount_options(fsopt, opt, other)) { |
---|
| 1005 | + if (compare_mount_options(fsopt, opt, fsc)) { |
---|
1024 | 1006 | dout("monitor(s)/mount options don't match\n"); |
---|
1025 | 1007 | return 0; |
---|
1026 | 1008 | } |
---|
1027 | 1009 | if ((opt->flags & CEPH_OPT_FSID) && |
---|
1028 | | - ceph_fsid_compare(&opt->fsid, &other->client->fsid)) { |
---|
| 1010 | + ceph_fsid_compare(&opt->fsid, &fsc->client->fsid)) { |
---|
1029 | 1011 | dout("fsid doesn't match\n"); |
---|
1030 | 1012 | return 0; |
---|
1031 | 1013 | } |
---|
1032 | | - if (fsopt->sb_flags != other->mount_options->sb_flags) { |
---|
| 1014 | + if (fc->sb_flags != (sb->s_flags & ~SB_BORN)) { |
---|
1033 | 1015 | dout("flags differ\n"); |
---|
1034 | 1016 | return 0; |
---|
1035 | 1017 | } |
---|
| 1018 | + |
---|
| 1019 | + if (fsc->blocklisted && !ceph_test_mount_opt(fsc, CLEANRECOVER)) { |
---|
| 1020 | + dout("client is blocklisted (and CLEANRECOVER is not set)\n"); |
---|
| 1021 | + return 0; |
---|
| 1022 | + } |
---|
| 1023 | + |
---|
| 1024 | + if (fsc->mount_state == CEPH_MOUNT_SHUTDOWN) { |
---|
| 1025 | + dout("client has been forcibly unmounted\n"); |
---|
| 1026 | + return 0; |
---|
| 1027 | + } |
---|
| 1028 | + |
---|
1036 | 1029 | return 1; |
---|
1037 | 1030 | } |
---|
1038 | 1031 | |
---|
.. | .. |
---|
1059 | 1052 | return 0; |
---|
1060 | 1053 | } |
---|
1061 | 1054 | |
---|
1062 | | -static struct dentry *ceph_mount(struct file_system_type *fs_type, |
---|
1063 | | - int flags, const char *dev_name, void *data) |
---|
| 1055 | +static int ceph_get_tree(struct fs_context *fc) |
---|
1064 | 1056 | { |
---|
| 1057 | + struct ceph_parse_opts_ctx *pctx = fc->fs_private; |
---|
1065 | 1058 | struct super_block *sb; |
---|
1066 | 1059 | struct ceph_fs_client *fsc; |
---|
1067 | 1060 | struct dentry *res; |
---|
| 1061 | + int (*compare_super)(struct super_block *, struct fs_context *) = |
---|
| 1062 | + ceph_compare_super; |
---|
1068 | 1063 | int err; |
---|
1069 | | - int (*compare_super)(struct super_block *, void *) = ceph_compare_super; |
---|
1070 | | - struct ceph_mount_options *fsopt = NULL; |
---|
1071 | | - struct ceph_options *opt = NULL; |
---|
1072 | 1064 | |
---|
1073 | | - dout("ceph_mount\n"); |
---|
| 1065 | + dout("ceph_get_tree\n"); |
---|
1074 | 1066 | |
---|
1075 | | -#ifdef CONFIG_CEPH_FS_POSIX_ACL |
---|
1076 | | - flags |= SB_POSIXACL; |
---|
1077 | | -#endif |
---|
1078 | | - err = parse_mount_options(&fsopt, &opt, flags, data, dev_name); |
---|
1079 | | - if (err < 0) { |
---|
1080 | | - res = ERR_PTR(err); |
---|
1081 | | - goto out_final; |
---|
1082 | | - } |
---|
| 1067 | + if (!fc->source) |
---|
| 1068 | + return invalfc(fc, "No source"); |
---|
1083 | 1069 | |
---|
1084 | 1070 | /* create client (which we may/may not use) */ |
---|
1085 | | - fsc = create_fs_client(fsopt, opt); |
---|
| 1071 | + fsc = create_fs_client(pctx->opts, pctx->copts); |
---|
| 1072 | + pctx->opts = NULL; |
---|
| 1073 | + pctx->copts = NULL; |
---|
1086 | 1074 | if (IS_ERR(fsc)) { |
---|
1087 | | - res = ERR_CAST(fsc); |
---|
| 1075 | + err = PTR_ERR(fsc); |
---|
1088 | 1076 | goto out_final; |
---|
1089 | 1077 | } |
---|
1090 | 1078 | |
---|
1091 | 1079 | err = ceph_mdsc_init(fsc); |
---|
1092 | | - if (err < 0) { |
---|
1093 | | - res = ERR_PTR(err); |
---|
| 1080 | + if (err < 0) |
---|
1094 | 1081 | goto out; |
---|
1095 | | - } |
---|
1096 | 1082 | |
---|
1097 | 1083 | if (ceph_test_opt(fsc->client, NOSHARE)) |
---|
1098 | 1084 | compare_super = NULL; |
---|
1099 | | - sb = sget(fs_type, compare_super, ceph_set_super, flags, fsc); |
---|
| 1085 | + |
---|
| 1086 | + fc->s_fs_info = fsc; |
---|
| 1087 | + sb = sget_fc(fc, compare_super, ceph_set_super); |
---|
| 1088 | + fc->s_fs_info = NULL; |
---|
1100 | 1089 | if (IS_ERR(sb)) { |
---|
1101 | | - res = ERR_CAST(sb); |
---|
| 1090 | + err = PTR_ERR(sb); |
---|
1102 | 1091 | goto out; |
---|
1103 | 1092 | } |
---|
1104 | 1093 | |
---|
1105 | 1094 | if (ceph_sb_to_client(sb) != fsc) { |
---|
1106 | | - ceph_mdsc_destroy(fsc); |
---|
1107 | 1095 | destroy_fs_client(fsc); |
---|
1108 | 1096 | fsc = ceph_sb_to_client(sb); |
---|
1109 | 1097 | dout("get_sb got existing client %p\n", fsc); |
---|
1110 | 1098 | } else { |
---|
1111 | 1099 | dout("get_sb using new client %p\n", fsc); |
---|
1112 | 1100 | err = ceph_setup_bdi(sb, fsc); |
---|
1113 | | - if (err < 0) { |
---|
1114 | | - res = ERR_PTR(err); |
---|
| 1101 | + if (err < 0) |
---|
1115 | 1102 | goto out_splat; |
---|
1116 | | - } |
---|
1117 | 1103 | } |
---|
1118 | 1104 | |
---|
1119 | | - res = ceph_real_mount(fsc); |
---|
1120 | | - if (IS_ERR(res)) |
---|
| 1105 | + res = ceph_real_mount(fsc, fc); |
---|
| 1106 | + if (IS_ERR(res)) { |
---|
| 1107 | + err = PTR_ERR(res); |
---|
1121 | 1108 | goto out_splat; |
---|
| 1109 | + } |
---|
1122 | 1110 | dout("root %p inode %p ino %llx.%llx\n", res, |
---|
1123 | 1111 | d_inode(res), ceph_vinop(d_inode(res))); |
---|
1124 | | - return res; |
---|
| 1112 | + fc->root = fsc->sb->s_root; |
---|
| 1113 | + return 0; |
---|
1125 | 1114 | |
---|
1126 | 1115 | out_splat: |
---|
1127 | 1116 | if (!ceph_mdsmap_is_cluster_available(fsc->mdsc->mdsmap)) { |
---|
.. | .. |
---|
1134 | 1123 | goto out_final; |
---|
1135 | 1124 | |
---|
1136 | 1125 | out: |
---|
1137 | | - ceph_mdsc_destroy(fsc); |
---|
1138 | 1126 | destroy_fs_client(fsc); |
---|
1139 | 1127 | out_final: |
---|
1140 | | - dout("ceph_mount fail %ld\n", PTR_ERR(res)); |
---|
1141 | | - return res; |
---|
| 1128 | + dout("ceph_get_tree fail %d\n", err); |
---|
| 1129 | + return err; |
---|
| 1130 | +} |
---|
| 1131 | + |
---|
| 1132 | +static void ceph_free_fc(struct fs_context *fc) |
---|
| 1133 | +{ |
---|
| 1134 | + struct ceph_parse_opts_ctx *pctx = fc->fs_private; |
---|
| 1135 | + |
---|
| 1136 | + if (pctx) { |
---|
| 1137 | + destroy_mount_options(pctx->opts); |
---|
| 1138 | + ceph_destroy_options(pctx->copts); |
---|
| 1139 | + kfree(pctx); |
---|
| 1140 | + } |
---|
| 1141 | +} |
---|
| 1142 | + |
---|
| 1143 | +static int ceph_reconfigure_fc(struct fs_context *fc) |
---|
| 1144 | +{ |
---|
| 1145 | + struct ceph_parse_opts_ctx *pctx = fc->fs_private; |
---|
| 1146 | + struct ceph_mount_options *fsopt = pctx->opts; |
---|
| 1147 | + struct ceph_fs_client *fsc = ceph_sb_to_client(fc->root->d_sb); |
---|
| 1148 | + |
---|
| 1149 | + if (fsopt->flags & CEPH_MOUNT_OPT_ASYNC_DIROPS) |
---|
| 1150 | + ceph_set_mount_opt(fsc, ASYNC_DIROPS); |
---|
| 1151 | + else |
---|
| 1152 | + ceph_clear_mount_opt(fsc, ASYNC_DIROPS); |
---|
| 1153 | + |
---|
| 1154 | + sync_filesystem(fc->root->d_sb); |
---|
| 1155 | + return 0; |
---|
| 1156 | +} |
---|
| 1157 | + |
---|
| 1158 | +static const struct fs_context_operations ceph_context_ops = { |
---|
| 1159 | + .free = ceph_free_fc, |
---|
| 1160 | + .parse_param = ceph_parse_mount_param, |
---|
| 1161 | + .get_tree = ceph_get_tree, |
---|
| 1162 | + .reconfigure = ceph_reconfigure_fc, |
---|
| 1163 | +}; |
---|
| 1164 | + |
---|
| 1165 | +/* |
---|
| 1166 | + * Set up the filesystem mount context. |
---|
| 1167 | + */ |
---|
| 1168 | +static int ceph_init_fs_context(struct fs_context *fc) |
---|
| 1169 | +{ |
---|
| 1170 | + struct ceph_parse_opts_ctx *pctx; |
---|
| 1171 | + struct ceph_mount_options *fsopt; |
---|
| 1172 | + |
---|
| 1173 | + pctx = kzalloc(sizeof(*pctx), GFP_KERNEL); |
---|
| 1174 | + if (!pctx) |
---|
| 1175 | + return -ENOMEM; |
---|
| 1176 | + |
---|
| 1177 | + pctx->copts = ceph_alloc_options(); |
---|
| 1178 | + if (!pctx->copts) |
---|
| 1179 | + goto nomem; |
---|
| 1180 | + |
---|
| 1181 | + pctx->opts = kzalloc(sizeof(*pctx->opts), GFP_KERNEL); |
---|
| 1182 | + if (!pctx->opts) |
---|
| 1183 | + goto nomem; |
---|
| 1184 | + |
---|
| 1185 | + fsopt = pctx->opts; |
---|
| 1186 | + fsopt->flags = CEPH_MOUNT_OPT_DEFAULT; |
---|
| 1187 | + |
---|
| 1188 | + fsopt->wsize = CEPH_MAX_WRITE_SIZE; |
---|
| 1189 | + fsopt->rsize = CEPH_MAX_READ_SIZE; |
---|
| 1190 | + fsopt->rasize = CEPH_RASIZE_DEFAULT; |
---|
| 1191 | + fsopt->snapdir_name = kstrdup(CEPH_SNAPDIRNAME_DEFAULT, GFP_KERNEL); |
---|
| 1192 | + if (!fsopt->snapdir_name) |
---|
| 1193 | + goto nomem; |
---|
| 1194 | + |
---|
| 1195 | + fsopt->caps_wanted_delay_min = CEPH_CAPS_WANTED_DELAY_MIN_DEFAULT; |
---|
| 1196 | + fsopt->caps_wanted_delay_max = CEPH_CAPS_WANTED_DELAY_MAX_DEFAULT; |
---|
| 1197 | + fsopt->max_readdir = CEPH_MAX_READDIR_DEFAULT; |
---|
| 1198 | + fsopt->max_readdir_bytes = CEPH_MAX_READDIR_BYTES_DEFAULT; |
---|
| 1199 | + fsopt->congestion_kb = default_congestion_kb(); |
---|
| 1200 | + |
---|
| 1201 | +#ifdef CONFIG_CEPH_FS_POSIX_ACL |
---|
| 1202 | + fc->sb_flags |= SB_POSIXACL; |
---|
| 1203 | +#endif |
---|
| 1204 | + |
---|
| 1205 | + fc->fs_private = pctx; |
---|
| 1206 | + fc->ops = &ceph_context_ops; |
---|
| 1207 | + return 0; |
---|
| 1208 | + |
---|
| 1209 | +nomem: |
---|
| 1210 | + destroy_mount_options(pctx->opts); |
---|
| 1211 | + ceph_destroy_options(pctx->copts); |
---|
| 1212 | + kfree(pctx); |
---|
| 1213 | + return -ENOMEM; |
---|
1142 | 1214 | } |
---|
1143 | 1215 | |
---|
1144 | 1216 | static void ceph_kill_sb(struct super_block *s) |
---|
1145 | 1217 | { |
---|
1146 | 1218 | struct ceph_fs_client *fsc = ceph_sb_to_client(s); |
---|
1147 | | - dev_t dev = s->s_dev; |
---|
1148 | 1219 | |
---|
1149 | 1220 | dout("kill_sb %p\n", s); |
---|
1150 | 1221 | |
---|
1151 | 1222 | ceph_mdsc_pre_umount(fsc->mdsc); |
---|
1152 | 1223 | flush_fs_workqueues(fsc); |
---|
1153 | 1224 | |
---|
1154 | | - generic_shutdown_super(s); |
---|
| 1225 | + /* |
---|
| 1226 | + * Though the kill_anon_super() will finally trigger the |
---|
| 1227 | + * sync_filesystem() anyway, we still need to do it here |
---|
| 1228 | + * and then bump the stage of shutdown to stop the work |
---|
| 1229 | + * queue as earlier as possible. |
---|
| 1230 | + */ |
---|
| 1231 | + sync_filesystem(s); |
---|
| 1232 | + |
---|
| 1233 | + fsc->mdsc->stopping = CEPH_MDSC_STOPPING_FLUSHED; |
---|
| 1234 | + |
---|
| 1235 | + kill_anon_super(s); |
---|
1155 | 1236 | |
---|
1156 | 1237 | fsc->client->extra_mon_dispatch = NULL; |
---|
1157 | 1238 | ceph_fs_debugfs_cleanup(fsc); |
---|
1158 | 1239 | |
---|
1159 | 1240 | ceph_fscache_unregister_fs(fsc); |
---|
1160 | 1241 | |
---|
1161 | | - ceph_mdsc_destroy(fsc); |
---|
1162 | | - |
---|
1163 | 1242 | destroy_fs_client(fsc); |
---|
1164 | | - free_anon_bdev(dev); |
---|
1165 | 1243 | } |
---|
1166 | 1244 | |
---|
1167 | 1245 | static struct file_system_type ceph_fs_type = { |
---|
1168 | 1246 | .owner = THIS_MODULE, |
---|
1169 | 1247 | .name = "ceph", |
---|
1170 | | - .mount = ceph_mount, |
---|
| 1248 | + .init_fs_context = ceph_init_fs_context, |
---|
1171 | 1249 | .kill_sb = ceph_kill_sb, |
---|
1172 | 1250 | .fs_flags = FS_RENAME_DOES_D_MOVE, |
---|
1173 | 1251 | }; |
---|
1174 | 1252 | MODULE_ALIAS_FS("ceph"); |
---|
| 1253 | + |
---|
| 1254 | +int ceph_force_reconnect(struct super_block *sb) |
---|
| 1255 | +{ |
---|
| 1256 | + struct ceph_fs_client *fsc = ceph_sb_to_client(sb); |
---|
| 1257 | + int err = 0; |
---|
| 1258 | + |
---|
| 1259 | + ceph_umount_begin(sb); |
---|
| 1260 | + |
---|
| 1261 | + /* Make sure all page caches get invalidated. |
---|
| 1262 | + * see remove_session_caps_cb() */ |
---|
| 1263 | + flush_workqueue(fsc->inode_wq); |
---|
| 1264 | + |
---|
| 1265 | + /* In case that we were blocklisted. This also reset |
---|
| 1266 | + * all mon/osd connections */ |
---|
| 1267 | + ceph_reset_client_addr(fsc->client); |
---|
| 1268 | + |
---|
| 1269 | + ceph_osdc_clear_abort_err(&fsc->client->osdc); |
---|
| 1270 | + |
---|
| 1271 | + fsc->blocklisted = false; |
---|
| 1272 | + fsc->mount_state = CEPH_MOUNT_MOUNTED; |
---|
| 1273 | + |
---|
| 1274 | + if (sb->s_root) { |
---|
| 1275 | + err = __ceph_do_getattr(d_inode(sb->s_root), NULL, |
---|
| 1276 | + CEPH_STAT_CAP_INODE, true); |
---|
| 1277 | + } |
---|
| 1278 | + return err; |
---|
| 1279 | +} |
---|
1175 | 1280 | |
---|
1176 | 1281 | static int __init init_ceph(void) |
---|
1177 | 1282 | { |
---|
.. | .. |
---|
1180 | 1285 | goto out; |
---|
1181 | 1286 | |
---|
1182 | 1287 | ceph_flock_init(); |
---|
1183 | | - ceph_xattr_init(); |
---|
1184 | 1288 | ret = register_filesystem(&ceph_fs_type); |
---|
1185 | 1289 | if (ret) |
---|
1186 | | - goto out_xattr; |
---|
| 1290 | + goto out_caches; |
---|
1187 | 1291 | |
---|
1188 | 1292 | pr_info("loaded (mds proto %d)\n", CEPH_MDSC_PROTOCOL); |
---|
1189 | 1293 | |
---|
1190 | 1294 | return 0; |
---|
1191 | 1295 | |
---|
1192 | | -out_xattr: |
---|
1193 | | - ceph_xattr_exit(); |
---|
| 1296 | +out_caches: |
---|
1194 | 1297 | destroy_caches(); |
---|
1195 | 1298 | out: |
---|
1196 | 1299 | return ret; |
---|
.. | .. |
---|
1200 | 1303 | { |
---|
1201 | 1304 | dout("exit_ceph\n"); |
---|
1202 | 1305 | unregister_filesystem(&ceph_fs_type); |
---|
1203 | | - ceph_xattr_exit(); |
---|
1204 | 1306 | destroy_caches(); |
---|
1205 | 1307 | } |
---|
| 1308 | + |
---|
| 1309 | +static int param_set_metrics(const char *val, const struct kernel_param *kp) |
---|
| 1310 | +{ |
---|
| 1311 | + struct ceph_fs_client *fsc; |
---|
| 1312 | + int ret; |
---|
| 1313 | + |
---|
| 1314 | + ret = param_set_bool(val, kp); |
---|
| 1315 | + if (ret) { |
---|
| 1316 | + pr_err("Failed to parse sending metrics switch value '%s'\n", |
---|
| 1317 | + val); |
---|
| 1318 | + return ret; |
---|
| 1319 | + } else if (!disable_send_metrics) { |
---|
| 1320 | + // wake up all the mds clients |
---|
| 1321 | + spin_lock(&ceph_fsc_lock); |
---|
| 1322 | + list_for_each_entry(fsc, &ceph_fsc_list, metric_wakeup) { |
---|
| 1323 | + metric_schedule_delayed(&fsc->mdsc->metric); |
---|
| 1324 | + } |
---|
| 1325 | + spin_unlock(&ceph_fsc_lock); |
---|
| 1326 | + } |
---|
| 1327 | + |
---|
| 1328 | + return 0; |
---|
| 1329 | +} |
---|
| 1330 | + |
---|
| 1331 | +static const struct kernel_param_ops param_ops_metrics = { |
---|
| 1332 | + .set = param_set_metrics, |
---|
| 1333 | + .get = param_get_bool, |
---|
| 1334 | +}; |
---|
| 1335 | + |
---|
| 1336 | +bool disable_send_metrics = false; |
---|
| 1337 | +module_param_cb(disable_send_metrics, ¶m_ops_metrics, &disable_send_metrics, 0644); |
---|
| 1338 | +MODULE_PARM_DESC(disable_send_metrics, "Enable sending perf metrics to ceph cluster (default: on)"); |
---|
1206 | 1339 | |
---|
1207 | 1340 | module_init(init_ceph); |
---|
1208 | 1341 | module_exit(exit_ceph); |
---|
.. | .. |
---|
1212 | 1345 | MODULE_AUTHOR("Patience Warnick <patience@newdream.net>"); |
---|
1213 | 1346 | MODULE_DESCRIPTION("Ceph filesystem for Linux"); |
---|
1214 | 1347 | MODULE_LICENSE("GPL"); |
---|
| 1348 | +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); |
---|