hc
2024-01-03 2f7c68cb55ecb7331f2381deb497c27155f32faf
kernel/fs/ceph/super.c
....@@ -1,3 +1,4 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12
23 #include <linux/ceph/ceph_debug.h>
34
....@@ -8,7 +9,8 @@
89 #include <linux/in6.h>
910 #include <linux/module.h>
1011 #include <linux/mount.h>
11
-#include <linux/parser.h>
12
+#include <linux/fs_context.h>
13
+#include <linux/fs_parser.h>
1214 #include <linux/sched.h>
1315 #include <linux/seq_file.h>
1416 #include <linux/slab.h>
....@@ -24,6 +26,9 @@
2426 #include <linux/ceph/mon_client.h>
2527 #include <linux/ceph/auth.h>
2628 #include <linux/ceph/debugfs.h>
29
+
30
+static DEFINE_SPINLOCK(ceph_fsc_lock);
31
+static LIST_HEAD(ceph_fsc_list);
2732
2833 /*
2934 * Ceph superblock operations
....@@ -47,8 +52,7 @@
4752 struct ceph_fs_client *fsc = ceph_inode_to_client(d_inode(dentry));
4853 struct ceph_mon_client *monc = &fsc->client->monc;
4954 struct ceph_statfs st;
50
- u64 fsid;
51
- int err;
55
+ int i, err;
5256 u64 data_pool;
5357
5458 if (fsc->mdsc->mdsmap->m_num_data_pg_pools == 1) {
....@@ -94,13 +98,14 @@
9498 buf->f_namelen = NAME_MAX;
9599
96100 /* Must convert the fsid, for consistent values across arches */
101
+ buf->f_fsid.val[0] = 0;
97102 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]);
100105 mutex_unlock(&monc->mutex);
101106
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;
104109
105110 return 0;
106111 }
....@@ -132,77 +137,74 @@
132137 Opt_rasize,
133138 Opt_caps_wanted_delay_min,
134139 Opt_caps_wanted_delay_max,
140
+ Opt_caps_max,
135141 Opt_readdir_max_entries,
136142 Opt_readdir_max_bytes,
137143 Opt_congestion_kb,
138
- Opt_last_int,
139144 /* int args above */
140145 Opt_snapdirname,
141146 Opt_mds_namespace,
142
- Opt_fscache_uniq,
143
- Opt_last_string,
147
+ Opt_recover_session,
148
+ Opt_source,
144149 /* string args above */
145150 Opt_dirstat,
146
- Opt_nodirstat,
147151 Opt_rbytes,
148
- Opt_norbytes,
149152 Opt_asyncreaddir,
150
- Opt_noasyncreaddir,
151153 Opt_dcache,
152
- Opt_nodcache,
153154 Opt_ino32,
154
- Opt_noino32,
155155 Opt_fscache,
156
- Opt_nofscache,
157156 Opt_poolperm,
158
- Opt_nopoolperm,
159157 Opt_require_active_mds,
160
- Opt_norequire_active_mds,
161
-#ifdef CONFIG_CEPH_FS_POSIX_ACL
162158 Opt_acl,
163
-#endif
164
- Opt_noacl,
165159 Opt_quotadf,
166
- Opt_noquotadf,
160
+ Opt_copyfrom,
161
+ Opt_wsync,
167162 };
168163
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;
206208 };
207209
208210 /*
....@@ -225,181 +227,249 @@
225227 path[j] = '\0';
226228 }
227229
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)
229240 {
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;
233245
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");
237249
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);
248262 } else {
249
- dout("got token %d\n", token);
263
+ dev_name_end = dev_name + strlen(dev_name);
250264 }
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;
251301
252302 switch (token) {
253303 case Opt_snapdirname:
254304 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;
260307 break;
261308 case Opt_mds_namespace:
262309 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;
268312 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();
278321 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);
283326 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);
287331 break;
288332 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);
292337 break;
293338 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);
297340 break;
298341 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;
302345 break;
303346 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;
307355 break;
308356 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;
312360 break;
313361 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;
317365 break;
318366 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;
322370 break;
323371 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;
328376 break;
329377 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;
334382 break;
335383 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;
340388 break;
341389 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;
346394 break;
347395 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;
349400 break;
350
- case Opt_noino32:
351
- fsopt->flags &= ~CEPH_MOUNT_OPT_INO32;
352
- break;
401
+
353402 case Opt_fscache:
354403 #ifdef CONFIG_CEPH_FSCACHE
355
- fsopt->flags |= CEPH_MOUNT_OPT_FSCACHE;
356404 kfree(fsopt->fscache_uniq);
357405 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
+ }
358413 break;
359414 #else
360
- pr_err("fscache support is disabled\n");
361
- return -EINVAL;
415
+ return invalfc(fc, "fscache support is disabled");
362416 #endif
363
- case Opt_nofscache:
364
- fsopt->flags &= ~CEPH_MOUNT_OPT_FSCACHE;
365
- kfree(fsopt->fscache_uniq);
366
- fsopt->fscache_uniq = NULL;
367
- break;
368417 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;
373422 break;
374423 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;
379428 break;
380429 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;
382434 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;
385440 break;
386
-#ifdef CONFIG_CEPH_FS_POSIX_ACL
387441 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");
390447 #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;
393457 break;
394458 default:
395
- BUG_ON(token);
459
+ BUG();
396460 }
397461 return 0;
462
+
463
+out_of_range:
464
+ return invalfc(fc, "%s out of range", param->key);
398465 }
399466
400467 static void destroy_mount_options(struct ceph_mount_options *args)
401468 {
402469 dout("destroy_mount_options %p\n", args);
470
+ if (!args)
471
+ return;
472
+
403473 kfree(args->snapdir_name);
404474 kfree(args->mds_namespace);
405475 kfree(args->server_path);
....@@ -450,95 +520,6 @@
450520 return ceph_compare_options(new_opt, fsc->client);
451521 }
452522
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
-
542523 /**
543524 * ceph_show_options - Show mount options in /proc/mounts
544525 * @m: seq_file to write to
....@@ -555,7 +536,7 @@
555536 seq_putc(m, ',');
556537 pos = m->count;
557538
558
- ret = ceph_print_client_options(m, fsc->client);
539
+ ret = ceph_print_client_options(m, fsc->client, false);
559540 if (ret)
560541 return ret;
561542
....@@ -582,32 +563,44 @@
582563 seq_puts(m, ",noquotadf");
583564
584565 #ifdef CONFIG_CEPH_FS_POSIX_ACL
585
- if (fsopt->sb_flags & SB_POSIXACL)
566
+ if (root->d_sb->s_flags & SB_POSIXACL)
586567 seq_puts(m, ",acl");
587568 else
588569 seq_puts(m, ",noacl");
589570 #endif
590571
572
+ if ((fsopt->flags & CEPH_MOUNT_OPT_NOCOPYFROM) == 0)
573
+ seq_puts(m, ",copyfrom");
574
+
591575 if (fsopt->mds_namespace)
592576 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
+
593584 if (fsopt->wsize != CEPH_MAX_WRITE_SIZE)
594
- seq_printf(m, ",wsize=%d", fsopt->wsize);
585
+ seq_printf(m, ",wsize=%u", fsopt->wsize);
595586 if (fsopt->rsize != CEPH_MAX_READ_SIZE)
596
- seq_printf(m, ",rsize=%d", fsopt->rsize);
587
+ seq_printf(m, ",rsize=%u", fsopt->rsize);
597588 if (fsopt->rasize != CEPH_RASIZE_DEFAULT)
598
- seq_printf(m, ",rasize=%d", fsopt->rasize);
589
+ seq_printf(m, ",rasize=%u", fsopt->rasize);
599590 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);
601594 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",
603596 fsopt->caps_wanted_delay_min);
604597 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",
606599 fsopt->caps_wanted_delay_max);
607600 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);
609602 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);
611604 if (strcmp(fsopt->snapdir_name, CEPH_SNAPDIRNAME_DEFAULT))
612605 seq_show_option(m, "snapdirname", fsopt->snapdir_name);
613606
....@@ -644,8 +637,6 @@
644637 struct ceph_options *opt)
645638 {
646639 struct ceph_fs_client *fsc;
647
- int page_count;
648
- size_t size;
649640 int err;
650641
651642 fsc = kzalloc(sizeof(*fsc), GFP_KERNEL);
....@@ -662,7 +653,7 @@
662653 opt = NULL; /* fsc->client now owns this */
663654
664655 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);
666657
667658 if (!fsopt->mds_namespace) {
668659 ceph_monc_want_map(&fsc->client->monc, CEPH_SUB_MDSMAP,
....@@ -676,6 +667,8 @@
676667
677668 fsc->sb = NULL;
678669 fsc->mount_state = CEPH_MOUNT_MOUNTING;
670
+ fsc->filp_gen = 1;
671
+ fsc->have_copy_from2 = true;
679672
680673 atomic_long_set(&fsc->writeback_count, 0);
681674
....@@ -684,35 +677,21 @@
684677 * The number of concurrent works can be high but they don't need
685678 * to be processed in parallel, limit concurrency.
686679 */
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)
689682 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;
696686
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);
707690
708691 return fsc;
709692
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);
716695 fail_client:
717696 ceph_destroy_client(fsc->client);
718697 fail:
....@@ -725,20 +704,21 @@
725704
726705 static void flush_fs_workqueues(struct ceph_fs_client *fsc)
727706 {
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);
731709 }
732710
733711 static void destroy_fs_client(struct ceph_fs_client *fsc)
734712 {
735713 dout("destroy_fs_client %p\n", fsc);
736714
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);
740718
741
- mempool_destroy(fsc->wb_pagevec_pool);
719
+ ceph_mdsc_destroy(fsc);
720
+ destroy_workqueue(fsc->inode_wq);
721
+ destroy_workqueue(fsc->cap_wq);
742722
743723 destroy_mount_options(fsc->mount_options);
744724
....@@ -757,6 +737,8 @@
757737 struct kmem_cache *ceph_dentry_cachep;
758738 struct kmem_cache *ceph_file_cachep;
759739 struct kmem_cache *ceph_dir_file_cachep;
740
+struct kmem_cache *ceph_mds_request_cachep;
741
+mempool_t *ceph_wb_pagevec_pool;
760742
761743 static void ceph_inode_init_once(void *foo)
762744 {
....@@ -797,6 +779,14 @@
797779 if (!ceph_dir_file_cachep)
798780 goto bad_dir_file;
799781
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
+
800790 error = ceph_fscache_register();
801791 if (error)
802792 goto bad_fscache;
....@@ -804,6 +794,10 @@
804794 return 0;
805795
806796 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:
807801 kmem_cache_destroy(ceph_dir_file_cachep);
808802 bad_dir_file:
809803 kmem_cache_destroy(ceph_file_cachep);
....@@ -832,12 +826,14 @@
832826 kmem_cache_destroy(ceph_dentry_cachep);
833827 kmem_cache_destroy(ceph_file_cachep);
834828 kmem_cache_destroy(ceph_dir_file_cachep);
829
+ kmem_cache_destroy(ceph_mds_request_cachep);
830
+ mempool_destroy(ceph_wb_pagevec_pool);
835831
836832 ceph_fscache_unregister();
837833 }
838834
839835 /*
840
- * ceph_umount_begin - initiate forced umount. Tear down down the
836
+ * ceph_umount_begin - initiate forced umount. Tear down the
841837 * mount, skipping steps that may hang while waiting for server(s).
842838 */
843839 static void ceph_umount_begin(struct super_block *sb)
....@@ -850,24 +846,17 @@
850846 fsc->mount_state = CEPH_MOUNT_SHUTDOWN;
851847 ceph_osdc_abort_requests(&fsc->client->osdc, -EIO);
852848 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
860850 }
861851
862852 static const struct super_operations ceph_super_ops = {
863853 .alloc_inode = ceph_alloc_inode,
864
- .destroy_inode = ceph_destroy_inode,
854
+ .free_inode = ceph_free_inode,
865855 .write_inode = ceph_write_inode,
866
- .drop_inode = ceph_drop_inode,
856
+ .drop_inode = generic_delete_inode,
867857 .evict_inode = ceph_evict_inode,
868858 .sync_fs = ceph_sync_fs,
869859 .put_super = ceph_put_super,
870
- .remount_fs = ceph_remount,
871860 .show_options = ceph_show_options,
872861 .statfs = ceph_statfs,
873862 .umount_begin = ceph_umount_begin,
....@@ -925,7 +914,8 @@
925914 /*
926915 * mount: join the ceph cluster, and open root directory.
927916 */
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)
929919 {
930920 int err;
931921 unsigned long started = jiffies; /* note the start time */
....@@ -944,16 +934,14 @@
944934
945935 /* setup fscache */
946936 if (fsc->mount_options->flags & CEPH_MOUNT_OPT_FSCACHE) {
947
- err = ceph_fscache_register_fs(fsc);
937
+ err = ceph_fscache_register_fs(fsc, fc);
948938 if (err < 0)
949939 goto out;
950940 }
951941
952942 dout("mount opening path '%s'\n", path);
953943
954
- err = ceph_fs_debugfs_init(fsc);
955
- if (err < 0)
956
- goto out;
944
+ ceph_fs_debugfs_init(fsc);
957945
958946 root = open_root_dentry(fsc, path, started);
959947 if (IS_ERR(root)) {
....@@ -975,18 +963,16 @@
975963 return ERR_PTR(err);
976964 }
977965
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)
979967 {
980
- struct ceph_fs_client *fsc = data;
968
+ struct ceph_fs_client *fsc = s->s_fs_info;
981969 int ret;
982970
983
- dout("set_super %p data %p\n", s, data);
971
+ dout("set_super %p\n", s);
984972
985
- s->s_flags = fsc->mount_options->sb_flags;
986973 s->s_maxbytes = MAX_LFS_FILESIZE;
987974
988975 s->s_xattr = ceph_xattr_handlers;
989
- s->s_fs_info = fsc;
990976 fsc->sb = s;
991977 fsc->max_file_size = 1ULL << 40; /* temp value until we get mdsmap */
992978
....@@ -994,45 +980,52 @@
994980 s->s_d_op = &ceph_dentry_ops;
995981 s->s_export_op = &ceph_export_ops;
996982
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;
998986
999
- ret = set_anon_super(s, NULL); /* what is that second arg for? */
987
+ ret = set_anon_super_fc(s, fc);
1000988 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;
1008990 return ret;
1009991 }
1010992
1011993 /*
1012994 * share superblock if same fs AND options
1013995 */
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)
1015997 {
1016
- struct ceph_fs_client *new = data;
998
+ struct ceph_fs_client *new = fc->s_fs_info;
1017999 struct ceph_mount_options *fsopt = new->mount_options;
10181000 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);
10201002
10211003 dout("ceph_compare_super %p\n", sb);
10221004
1023
- if (compare_mount_options(fsopt, opt, other)) {
1005
+ if (compare_mount_options(fsopt, opt, fsc)) {
10241006 dout("monitor(s)/mount options don't match\n");
10251007 return 0;
10261008 }
10271009 if ((opt->flags & CEPH_OPT_FSID) &&
1028
- ceph_fsid_compare(&opt->fsid, &other->client->fsid)) {
1010
+ ceph_fsid_compare(&opt->fsid, &fsc->client->fsid)) {
10291011 dout("fsid doesn't match\n");
10301012 return 0;
10311013 }
1032
- if (fsopt->sb_flags != other->mount_options->sb_flags) {
1014
+ if (fc->sb_flags != (sb->s_flags & ~SB_BORN)) {
10331015 dout("flags differ\n");
10341016 return 0;
10351017 }
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
+
10361029 return 1;
10371030 }
10381031
....@@ -1059,69 +1052,65 @@
10591052 return 0;
10601053 }
10611054
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)
10641056 {
1057
+ struct ceph_parse_opts_ctx *pctx = fc->fs_private;
10651058 struct super_block *sb;
10661059 struct ceph_fs_client *fsc;
10671060 struct dentry *res;
1061
+ int (*compare_super)(struct super_block *, struct fs_context *) =
1062
+ ceph_compare_super;
10681063 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;
10721064
1073
- dout("ceph_mount\n");
1065
+ dout("ceph_get_tree\n");
10741066
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");
10831069
10841070 /* 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;
10861074 if (IS_ERR(fsc)) {
1087
- res = ERR_CAST(fsc);
1075
+ err = PTR_ERR(fsc);
10881076 goto out_final;
10891077 }
10901078
10911079 err = ceph_mdsc_init(fsc);
1092
- if (err < 0) {
1093
- res = ERR_PTR(err);
1080
+ if (err < 0)
10941081 goto out;
1095
- }
10961082
10971083 if (ceph_test_opt(fsc->client, NOSHARE))
10981084 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;
11001089 if (IS_ERR(sb)) {
1101
- res = ERR_CAST(sb);
1090
+ err = PTR_ERR(sb);
11021091 goto out;
11031092 }
11041093
11051094 if (ceph_sb_to_client(sb) != fsc) {
1106
- ceph_mdsc_destroy(fsc);
11071095 destroy_fs_client(fsc);
11081096 fsc = ceph_sb_to_client(sb);
11091097 dout("get_sb got existing client %p\n", fsc);
11101098 } else {
11111099 dout("get_sb using new client %p\n", fsc);
11121100 err = ceph_setup_bdi(sb, fsc);
1113
- if (err < 0) {
1114
- res = ERR_PTR(err);
1101
+ if (err < 0)
11151102 goto out_splat;
1116
- }
11171103 }
11181104
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);
11211108 goto out_splat;
1109
+ }
11221110 dout("root %p inode %p ino %llx.%llx\n", res,
11231111 d_inode(res), ceph_vinop(d_inode(res)));
1124
- return res;
1112
+ fc->root = fsc->sb->s_root;
1113
+ return 0;
11251114
11261115 out_splat:
11271116 if (!ceph_mdsmap_is_cluster_available(fsc->mdsc->mdsmap)) {
....@@ -1134,44 +1123,160 @@
11341123 goto out_final;
11351124
11361125 out:
1137
- ceph_mdsc_destroy(fsc);
11381126 destroy_fs_client(fsc);
11391127 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;
11421214 }
11431215
11441216 static void ceph_kill_sb(struct super_block *s)
11451217 {
11461218 struct ceph_fs_client *fsc = ceph_sb_to_client(s);
1147
- dev_t dev = s->s_dev;
11481219
11491220 dout("kill_sb %p\n", s);
11501221
11511222 ceph_mdsc_pre_umount(fsc->mdsc);
11521223 flush_fs_workqueues(fsc);
11531224
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);
11551236
11561237 fsc->client->extra_mon_dispatch = NULL;
11571238 ceph_fs_debugfs_cleanup(fsc);
11581239
11591240 ceph_fscache_unregister_fs(fsc);
11601241
1161
- ceph_mdsc_destroy(fsc);
1162
-
11631242 destroy_fs_client(fsc);
1164
- free_anon_bdev(dev);
11651243 }
11661244
11671245 static struct file_system_type ceph_fs_type = {
11681246 .owner = THIS_MODULE,
11691247 .name = "ceph",
1170
- .mount = ceph_mount,
1248
+ .init_fs_context = ceph_init_fs_context,
11711249 .kill_sb = ceph_kill_sb,
11721250 .fs_flags = FS_RENAME_DOES_D_MOVE,
11731251 };
11741252 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
+}
11751280
11761281 static int __init init_ceph(void)
11771282 {
....@@ -1180,17 +1285,15 @@
11801285 goto out;
11811286
11821287 ceph_flock_init();
1183
- ceph_xattr_init();
11841288 ret = register_filesystem(&ceph_fs_type);
11851289 if (ret)
1186
- goto out_xattr;
1290
+ goto out_caches;
11871291
11881292 pr_info("loaded (mds proto %d)\n", CEPH_MDSC_PROTOCOL);
11891293
11901294 return 0;
11911295
1192
-out_xattr:
1193
- ceph_xattr_exit();
1296
+out_caches:
11941297 destroy_caches();
11951298 out:
11961299 return ret;
....@@ -1200,9 +1303,39 @@
12001303 {
12011304 dout("exit_ceph\n");
12021305 unregister_filesystem(&ceph_fs_type);
1203
- ceph_xattr_exit();
12041306 destroy_caches();
12051307 }
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, &param_ops_metrics, &disable_send_metrics, 0644);
1338
+MODULE_PARM_DESC(disable_send_metrics, "Enable sending perf metrics to ceph cluster (default: on)");
12061339
12071340 module_init(init_ceph);
12081341 module_exit(exit_ceph);
....@@ -1212,3 +1345,4 @@
12121345 MODULE_AUTHOR("Patience Warnick <patience@newdream.net>");
12131346 MODULE_DESCRIPTION("Ceph filesystem for Linux");
12141347 MODULE_LICENSE("GPL");
1348
+MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY);