106 |
106 |
return 0;
|
107 |
107 |
}
|
108 |
108 |
|
109 |
|
|
110 |
109 |
static int ceph_sync_fs(struct super_block *sb, int wait)
|
111 |
110 |
{
|
112 |
111 |
struct ceph_fs_client *fsc = ceph_sb_to_client(sb);
|
... | ... | |
430 |
429 |
return strcmp(s1, s2);
|
431 |
430 |
}
|
432 |
431 |
|
|
432 |
/**
|
|
433 |
* path_remove_extra_slash - Remove the extra slashes in the server path
|
|
434 |
* @server_path: the server path and could be NULL
|
|
435 |
*
|
|
436 |
* Return NULL if the path is NULL or only consists of "/", or a string
|
|
437 |
* without any extra slashes including the leading slash(es) and the
|
|
438 |
* slash(es) at the end of the server path, such as:
|
|
439 |
* "//dir1////dir2///" --> "dir1/dir2"
|
|
440 |
*/
|
|
441 |
static char *path_remove_extra_slash(const char *server_path)
|
|
442 |
{
|
|
443 |
const char *path = server_path;
|
|
444 |
const char *cur, *end;
|
|
445 |
char *buf, *p;
|
|
446 |
int len;
|
|
447 |
|
|
448 |
/* if the server path is omitted */
|
|
449 |
if (!path)
|
|
450 |
return NULL;
|
|
451 |
|
|
452 |
/* remove all the leading slashes */
|
|
453 |
while (*path == '/')
|
|
454 |
path++;
|
|
455 |
|
|
456 |
/* if the server path only consists of slashes */
|
|
457 |
if (*path == '\0')
|
|
458 |
return NULL;
|
|
459 |
|
|
460 |
len = strlen(path);
|
|
461 |
|
|
462 |
buf = kmalloc(len + 1, GFP_KERNEL);
|
|
463 |
if (!buf)
|
|
464 |
return ERR_PTR(-ENOMEM);
|
|
465 |
|
|
466 |
end = path + len;
|
|
467 |
p = buf;
|
|
468 |
do {
|
|
469 |
cur = strchr(path, '/');
|
|
470 |
if (!cur)
|
|
471 |
cur = end;
|
|
472 |
|
|
473 |
len = cur - path;
|
|
474 |
|
|
475 |
/* including one '/' */
|
|
476 |
if (cur != end)
|
|
477 |
len += 1;
|
|
478 |
|
|
479 |
memcpy(p, path, len);
|
|
480 |
p += len;
|
|
481 |
|
|
482 |
while (cur <= end && *cur == '/')
|
|
483 |
cur++;
|
|
484 |
path = cur;
|
|
485 |
} while (path < end);
|
|
486 |
|
|
487 |
*p = '\0';
|
|
488 |
|
|
489 |
/*
|
|
490 |
* remove the last slash if there has and just to make sure that
|
|
491 |
* we will get something like "dir1/dir2"
|
|
492 |
*/
|
|
493 |
if (*(--p) == '/')
|
|
494 |
*p = '\0';
|
|
495 |
|
|
496 |
return buf;
|
|
497 |
}
|
|
498 |
|
433 |
499 |
static int compare_mount_options(struct ceph_mount_options *new_fsopt,
|
434 |
500 |
struct ceph_options *new_opt,
|
435 |
501 |
struct ceph_fs_client *fsc)
|
... | ... | |
437 |
503 |
struct ceph_mount_options *fsopt1 = new_fsopt;
|
438 |
504 |
struct ceph_mount_options *fsopt2 = fsc->mount_options;
|
439 |
505 |
int ofs = offsetof(struct ceph_mount_options, snapdir_name);
|
|
506 |
char *p1, *p2;
|
440 |
507 |
int ret;
|
441 |
508 |
|
442 |
509 |
ret = memcmp(fsopt1, fsopt2, ofs);
|
... | ... | |
449 |
516 |
ret = strcmp_null(fsopt1->mds_namespace, fsopt2->mds_namespace);
|
450 |
517 |
if (ret)
|
451 |
518 |
return ret;
|
452 |
|
ret = strcmp_null(fsopt1->server_path, fsopt2->server_path);
|
|
519 |
|
|
520 |
p1 = path_remove_extra_slash(fsopt1->server_path);
|
|
521 |
if (IS_ERR(p1))
|
|
522 |
return PTR_ERR(p1);
|
|
523 |
p2 = path_remove_extra_slash(fsopt2->server_path);
|
|
524 |
if (IS_ERR(p2)) {
|
|
525 |
kfree(p1);
|
|
526 |
return PTR_ERR(p2);
|
|
527 |
}
|
|
528 |
ret = strcmp_null(p1, p2);
|
|
529 |
kfree(p1);
|
|
530 |
kfree(p2);
|
453 |
531 |
if (ret)
|
454 |
532 |
return ret;
|
|
533 |
|
455 |
534 |
ret = strcmp_null(fsopt1->fscache_uniq, fsopt2->fscache_uniq);
|
456 |
535 |
if (ret)
|
457 |
536 |
return ret;
|
... | ... | |
507 |
586 |
*/
|
508 |
587 |
dev_name_end = strchr(dev_name, '/');
|
509 |
588 |
if (dev_name_end) {
|
510 |
|
if (strlen(dev_name_end) > 1) {
|
511 |
|
fsopt->server_path = kstrdup(dev_name_end, GFP_KERNEL);
|
512 |
|
if (!fsopt->server_path) {
|
513 |
|
err = -ENOMEM;
|
514 |
|
goto out;
|
515 |
|
}
|
|
589 |
/*
|
|
590 |
* The server_path will include the whole chars from userland
|
|
591 |
* including the leading '/'.
|
|
592 |
*/
|
|
593 |
fsopt->server_path = kstrdup(dev_name_end, GFP_KERNEL);
|
|
594 |
if (!fsopt->server_path) {
|
|
595 |
err = -ENOMEM;
|
|
596 |
goto out;
|
516 |
597 |
}
|
517 |
598 |
} else {
|
518 |
599 |
dev_name_end = dev_name + strlen(dev_name);
|
... | ... | |
842 |
923 |
ceph_fscache_unregister();
|
843 |
924 |
}
|
844 |
925 |
|
845 |
|
|
846 |
926 |
/*
|
847 |
927 |
* ceph_umount_begin - initiate forced umount. Tear down down the
|
848 |
928 |
* mount, skipping steps that may hang while waiting for server(s).
|
... | ... | |
929 |
1009 |
return root;
|
930 |
1010 |
}
|
931 |
1011 |
|
932 |
|
|
933 |
|
|
934 |
|
|
935 |
1012 |
/*
|
936 |
1013 |
* mount: join the ceph cluster, and open root directory.
|
937 |
1014 |
*/
|
... | ... | |
945 |
1022 |
mutex_lock(&fsc->client->mount_mutex);
|
946 |
1023 |
|
947 |
1024 |
if (!fsc->sb->s_root) {
|
948 |
|
const char *path;
|
|
1025 |
const char *path, *p;
|
949 |
1026 |
err = __ceph_open_session(fsc->client, started);
|
950 |
1027 |
if (err < 0)
|
951 |
1028 |
goto out;
|
... | ... | |
957 |
1034 |
goto out;
|
958 |
1035 |
}
|
959 |
1036 |
|
960 |
|
if (!fsc->mount_options->server_path) {
|
961 |
|
path = "";
|
962 |
|
dout("mount opening path \\t\n");
|
963 |
|
} else {
|
964 |
|
path = fsc->mount_options->server_path + 1;
|
965 |
|
dout("mount opening path %s\n", path);
|
|
1037 |
p = path_remove_extra_slash(fsc->mount_options->server_path);
|
|
1038 |
if (IS_ERR(p)) {
|
|
1039 |
err = PTR_ERR(p);
|
|
1040 |
goto out;
|
966 |
1041 |
}
|
|
1042 |
/* if the server path is omitted or just consists of '/' */
|
|
1043 |
if (!p)
|
|
1044 |
path = "";
|
|
1045 |
else
|
|
1046 |
path = p;
|
|
1047 |
dout("mount opening path '%s'\n", path);
|
967 |
1048 |
|
968 |
1049 |
ceph_fs_debugfs_init(fsc);
|
969 |
1050 |
|
970 |
1051 |
root = open_root_dentry(fsc, path, started);
|
|
1052 |
kfree(p);
|
971 |
1053 |
if (IS_ERR(root)) {
|
972 |
1054 |
err = PTR_ERR(root);
|
973 |
1055 |
goto out;
|