diff options
author | David Howells <dhowells@redhat.com> | 2020-04-27 17:01:09 +0300 |
---|---|---|
committer | David Howells <dhowells@redhat.com> | 2020-06-04 17:37:57 +0300 |
commit | 6dfdf5369c9f0a47920b2f743434c90798f26cd5 (patch) | |
tree | 037656c0d187b7dbe2657311511bf86136719f1c | |
parent | 6ef350b1842081bef7e4879993f47f052b7007e7 (diff) | |
download | linux-6dfdf5369c9f0a47920b2f743434c90798f26cd5.tar.xz |
afs: Detect cell aliases 3 - YFS Cells with a canonical cell name op
YFS Volume Location servers have an operation by which the cell name may be
queried. Use this to find out what a YFS server thinks the canonical cell
name should be.
Signed-off-by: David Howells <dhowells@redhat.com>
-rw-r--r-- | fs/afs/vl_alias.c | 58 | ||||
-rw-r--r-- | fs/afs/vl_rotate.c | 4 |
2 files changed, 62 insertions, 0 deletions
diff --git a/fs/afs/vl_alias.c b/fs/afs/vl_alias.c index 76bfa4dde4a4..ac7a59e951ed 100644 --- a/fs/afs/vl_alias.c +++ b/fs/afs/vl_alias.c @@ -268,12 +268,70 @@ is_alias: return 1; } +/* + * Look up a VLDB record for a volume. + */ +static char *afs_vl_get_cell_name(struct afs_cell *cell, struct key *key) +{ + struct afs_vl_cursor vc; + char *cell_name = ERR_PTR(-EDESTADDRREQ); + bool skipped = false, not_skipped = false; + int ret; + + if (!afs_begin_vlserver_operation(&vc, cell, key)) + return ERR_PTR(-ERESTARTSYS); + + while (afs_select_vlserver(&vc)) { + if (!test_bit(AFS_VLSERVER_FL_IS_YFS, &vc.server->flags)) { + vc.ac.error = -EOPNOTSUPP; + skipped = true; + continue; + } + not_skipped = true; + cell_name = afs_yfsvl_get_cell_name(&vc); + } + + ret = afs_end_vlserver_operation(&vc); + if (skipped && !not_skipped) + ret = -EOPNOTSUPP; + return ret < 0 ? ERR_PTR(ret) : cell_name; +} + +static int yfs_check_canonical_cell_name(struct afs_cell *cell, struct key *key) +{ + struct afs_cell *master; + char *cell_name; + + cell_name = afs_vl_get_cell_name(cell, key); + if (IS_ERR(cell_name)) + return PTR_ERR(cell_name); + + if (strcmp(cell_name, cell->name) == 0) { + kfree(cell_name); + return 0; + } + + master = afs_lookup_cell(cell->net, cell_name, strlen(cell_name), + NULL, false); + kfree(cell_name); + if (IS_ERR(master)) + return PTR_ERR(master); + + cell->alias_of = master; /* Transfer our ref */ + return 1; +} + static int afs_do_cell_detect_alias(struct afs_cell *cell, struct key *key) { struct afs_volume *root_volume; + int ret; _enter("%s", cell->name); + ret = yfs_check_canonical_cell_name(cell, key); + if (ret != -EOPNOTSUPP) + return ret; + /* Try and get the root.cell volume for comparison with other cells */ root_volume = afs_sample_volume(cell, key, "root.cell", 9); if (!IS_ERR(root_volume)) { diff --git a/fs/afs/vl_rotate.c b/fs/afs/vl_rotate.c index 72eacc14e6e1..f405ca8b240a 100644 --- a/fs/afs/vl_rotate.c +++ b/fs/afs/vl_rotate.c @@ -151,6 +151,10 @@ bool afs_select_vlserver(struct afs_vl_cursor *vc) vc->error = error; vc->flags |= AFS_VL_CURSOR_RETRY; goto next_server; + + case -EOPNOTSUPP: + _debug("notsupp"); + goto next_server; } restart_from_beginning: |