18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* AFS cell alias detection 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 2020 Red Hat, Inc. All Rights Reserved. 58c2ecf20Sopenharmony_ci * Written by David Howells (dhowells@redhat.com) 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/slab.h> 98c2ecf20Sopenharmony_ci#include <linux/sched.h> 108c2ecf20Sopenharmony_ci#include <linux/namei.h> 118c2ecf20Sopenharmony_ci#include <keys/rxrpc-type.h> 128c2ecf20Sopenharmony_ci#include "internal.h" 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci/* 158c2ecf20Sopenharmony_ci * Sample a volume. 168c2ecf20Sopenharmony_ci */ 178c2ecf20Sopenharmony_cistatic struct afs_volume *afs_sample_volume(struct afs_cell *cell, struct key *key, 188c2ecf20Sopenharmony_ci const char *name, unsigned int namelen) 198c2ecf20Sopenharmony_ci{ 208c2ecf20Sopenharmony_ci struct afs_volume *volume; 218c2ecf20Sopenharmony_ci struct afs_fs_context fc = { 228c2ecf20Sopenharmony_ci .type = 0, /* Explicitly leave it to the VLDB */ 238c2ecf20Sopenharmony_ci .volnamesz = namelen, 248c2ecf20Sopenharmony_ci .volname = name, 258c2ecf20Sopenharmony_ci .net = cell->net, 268c2ecf20Sopenharmony_ci .cell = cell, 278c2ecf20Sopenharmony_ci .key = key, /* This might need to be something */ 288c2ecf20Sopenharmony_ci }; 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci volume = afs_create_volume(&fc); 318c2ecf20Sopenharmony_ci _leave(" = %p", volume); 328c2ecf20Sopenharmony_ci return volume; 338c2ecf20Sopenharmony_ci} 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci/* 368c2ecf20Sopenharmony_ci * Compare two addresses. 378c2ecf20Sopenharmony_ci */ 388c2ecf20Sopenharmony_cistatic int afs_compare_addrs(const struct sockaddr_rxrpc *srx_a, 398c2ecf20Sopenharmony_ci const struct sockaddr_rxrpc *srx_b) 408c2ecf20Sopenharmony_ci{ 418c2ecf20Sopenharmony_ci short port_a, port_b; 428c2ecf20Sopenharmony_ci int addr_a, addr_b, diff; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci diff = (short)srx_a->transport_type - (short)srx_b->transport_type; 458c2ecf20Sopenharmony_ci if (diff) 468c2ecf20Sopenharmony_ci goto out; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci switch (srx_a->transport_type) { 498c2ecf20Sopenharmony_ci case AF_INET: { 508c2ecf20Sopenharmony_ci const struct sockaddr_in *a = &srx_a->transport.sin; 518c2ecf20Sopenharmony_ci const struct sockaddr_in *b = &srx_b->transport.sin; 528c2ecf20Sopenharmony_ci addr_a = ntohl(a->sin_addr.s_addr); 538c2ecf20Sopenharmony_ci addr_b = ntohl(b->sin_addr.s_addr); 548c2ecf20Sopenharmony_ci diff = addr_a - addr_b; 558c2ecf20Sopenharmony_ci if (diff == 0) { 568c2ecf20Sopenharmony_ci port_a = ntohs(a->sin_port); 578c2ecf20Sopenharmony_ci port_b = ntohs(b->sin_port); 588c2ecf20Sopenharmony_ci diff = port_a - port_b; 598c2ecf20Sopenharmony_ci } 608c2ecf20Sopenharmony_ci break; 618c2ecf20Sopenharmony_ci } 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci case AF_INET6: { 648c2ecf20Sopenharmony_ci const struct sockaddr_in6 *a = &srx_a->transport.sin6; 658c2ecf20Sopenharmony_ci const struct sockaddr_in6 *b = &srx_b->transport.sin6; 668c2ecf20Sopenharmony_ci diff = memcmp(&a->sin6_addr, &b->sin6_addr, 16); 678c2ecf20Sopenharmony_ci if (diff == 0) { 688c2ecf20Sopenharmony_ci port_a = ntohs(a->sin6_port); 698c2ecf20Sopenharmony_ci port_b = ntohs(b->sin6_port); 708c2ecf20Sopenharmony_ci diff = port_a - port_b; 718c2ecf20Sopenharmony_ci } 728c2ecf20Sopenharmony_ci break; 738c2ecf20Sopenharmony_ci } 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci default: 768c2ecf20Sopenharmony_ci WARN_ON(1); 778c2ecf20Sopenharmony_ci diff = 1; 788c2ecf20Sopenharmony_ci } 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ciout: 818c2ecf20Sopenharmony_ci return diff; 828c2ecf20Sopenharmony_ci} 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci/* 858c2ecf20Sopenharmony_ci * Compare the address lists of a pair of fileservers. 868c2ecf20Sopenharmony_ci */ 878c2ecf20Sopenharmony_cistatic int afs_compare_fs_alists(const struct afs_server *server_a, 888c2ecf20Sopenharmony_ci const struct afs_server *server_b) 898c2ecf20Sopenharmony_ci{ 908c2ecf20Sopenharmony_ci const struct afs_addr_list *la, *lb; 918c2ecf20Sopenharmony_ci int a = 0, b = 0, addr_matches = 0; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci la = rcu_dereference(server_a->addresses); 948c2ecf20Sopenharmony_ci lb = rcu_dereference(server_b->addresses); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci while (a < la->nr_addrs && b < lb->nr_addrs) { 978c2ecf20Sopenharmony_ci const struct sockaddr_rxrpc *srx_a = &la->addrs[a]; 988c2ecf20Sopenharmony_ci const struct sockaddr_rxrpc *srx_b = &lb->addrs[b]; 998c2ecf20Sopenharmony_ci int diff = afs_compare_addrs(srx_a, srx_b); 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci if (diff < 0) { 1028c2ecf20Sopenharmony_ci a++; 1038c2ecf20Sopenharmony_ci } else if (diff > 0) { 1048c2ecf20Sopenharmony_ci b++; 1058c2ecf20Sopenharmony_ci } else { 1068c2ecf20Sopenharmony_ci addr_matches++; 1078c2ecf20Sopenharmony_ci a++; 1088c2ecf20Sopenharmony_ci b++; 1098c2ecf20Sopenharmony_ci } 1108c2ecf20Sopenharmony_ci } 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci return addr_matches; 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci/* 1168c2ecf20Sopenharmony_ci * Compare the fileserver lists of two volumes. The server lists are sorted in 1178c2ecf20Sopenharmony_ci * order of ascending UUID. 1188c2ecf20Sopenharmony_ci */ 1198c2ecf20Sopenharmony_cistatic int afs_compare_volume_slists(const struct afs_volume *vol_a, 1208c2ecf20Sopenharmony_ci const struct afs_volume *vol_b) 1218c2ecf20Sopenharmony_ci{ 1228c2ecf20Sopenharmony_ci const struct afs_server_list *la, *lb; 1238c2ecf20Sopenharmony_ci int i, a = 0, b = 0, uuid_matches = 0, addr_matches = 0; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci la = rcu_dereference(vol_a->servers); 1268c2ecf20Sopenharmony_ci lb = rcu_dereference(vol_b->servers); 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci for (i = 0; i < AFS_MAXTYPES; i++) 1298c2ecf20Sopenharmony_ci if (la->vids[i] != lb->vids[i]) 1308c2ecf20Sopenharmony_ci return 0; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci while (a < la->nr_servers && b < lb->nr_servers) { 1338c2ecf20Sopenharmony_ci const struct afs_server *server_a = la->servers[a].server; 1348c2ecf20Sopenharmony_ci const struct afs_server *server_b = lb->servers[b].server; 1358c2ecf20Sopenharmony_ci int diff = memcmp(&server_a->uuid, &server_b->uuid, sizeof(uuid_t)); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci if (diff < 0) { 1388c2ecf20Sopenharmony_ci a++; 1398c2ecf20Sopenharmony_ci } else if (diff > 0) { 1408c2ecf20Sopenharmony_ci b++; 1418c2ecf20Sopenharmony_ci } else { 1428c2ecf20Sopenharmony_ci uuid_matches++; 1438c2ecf20Sopenharmony_ci addr_matches += afs_compare_fs_alists(server_a, server_b); 1448c2ecf20Sopenharmony_ci a++; 1458c2ecf20Sopenharmony_ci b++; 1468c2ecf20Sopenharmony_ci } 1478c2ecf20Sopenharmony_ci } 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci _leave(" = %d [um %d]", addr_matches, uuid_matches); 1508c2ecf20Sopenharmony_ci return addr_matches; 1518c2ecf20Sopenharmony_ci} 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci/* 1548c2ecf20Sopenharmony_ci * Compare root.cell volumes. 1558c2ecf20Sopenharmony_ci */ 1568c2ecf20Sopenharmony_cistatic int afs_compare_cell_roots(struct afs_cell *cell) 1578c2ecf20Sopenharmony_ci{ 1588c2ecf20Sopenharmony_ci struct afs_cell *p; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci _enter(""); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci rcu_read_lock(); 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci hlist_for_each_entry_rcu(p, &cell->net->proc_cells, proc_link) { 1658c2ecf20Sopenharmony_ci if (p == cell || p->alias_of) 1668c2ecf20Sopenharmony_ci continue; 1678c2ecf20Sopenharmony_ci if (!p->root_volume) 1688c2ecf20Sopenharmony_ci continue; /* Ignore cells that don't have a root.cell volume. */ 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci if (afs_compare_volume_slists(cell->root_volume, p->root_volume) != 0) 1718c2ecf20Sopenharmony_ci goto is_alias; 1728c2ecf20Sopenharmony_ci } 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci rcu_read_unlock(); 1758c2ecf20Sopenharmony_ci _leave(" = 0"); 1768c2ecf20Sopenharmony_ci return 0; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ciis_alias: 1798c2ecf20Sopenharmony_ci rcu_read_unlock(); 1808c2ecf20Sopenharmony_ci cell->alias_of = afs_use_cell(p, afs_cell_trace_use_alias); 1818c2ecf20Sopenharmony_ci return 1; 1828c2ecf20Sopenharmony_ci} 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci/* 1858c2ecf20Sopenharmony_ci * Query the new cell for a volume from a cell we're already using. 1868c2ecf20Sopenharmony_ci */ 1878c2ecf20Sopenharmony_cistatic int afs_query_for_alias_one(struct afs_cell *cell, struct key *key, 1888c2ecf20Sopenharmony_ci struct afs_cell *p) 1898c2ecf20Sopenharmony_ci{ 1908c2ecf20Sopenharmony_ci struct afs_volume *volume, *pvol = NULL; 1918c2ecf20Sopenharmony_ci int ret; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci /* Arbitrarily pick a volume from the list. */ 1948c2ecf20Sopenharmony_ci read_seqlock_excl(&p->volume_lock); 1958c2ecf20Sopenharmony_ci if (!RB_EMPTY_ROOT(&p->volumes)) 1968c2ecf20Sopenharmony_ci pvol = afs_get_volume(rb_entry(p->volumes.rb_node, 1978c2ecf20Sopenharmony_ci struct afs_volume, cell_node), 1988c2ecf20Sopenharmony_ci afs_volume_trace_get_query_alias); 1998c2ecf20Sopenharmony_ci read_sequnlock_excl(&p->volume_lock); 2008c2ecf20Sopenharmony_ci if (!pvol) 2018c2ecf20Sopenharmony_ci return 0; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci _enter("%s:%s", cell->name, pvol->name); 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci /* And see if it's in the new cell. */ 2068c2ecf20Sopenharmony_ci volume = afs_sample_volume(cell, key, pvol->name, pvol->name_len); 2078c2ecf20Sopenharmony_ci if (IS_ERR(volume)) { 2088c2ecf20Sopenharmony_ci afs_put_volume(cell->net, pvol, afs_volume_trace_put_query_alias); 2098c2ecf20Sopenharmony_ci if (PTR_ERR(volume) != -ENOMEDIUM) 2108c2ecf20Sopenharmony_ci return PTR_ERR(volume); 2118c2ecf20Sopenharmony_ci /* That volume is not in the new cell, so not an alias */ 2128c2ecf20Sopenharmony_ci return 0; 2138c2ecf20Sopenharmony_ci } 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci /* The new cell has a like-named volume also - compare volume ID, 2168c2ecf20Sopenharmony_ci * server and address lists. 2178c2ecf20Sopenharmony_ci */ 2188c2ecf20Sopenharmony_ci ret = 0; 2198c2ecf20Sopenharmony_ci if (pvol->vid == volume->vid) { 2208c2ecf20Sopenharmony_ci rcu_read_lock(); 2218c2ecf20Sopenharmony_ci if (afs_compare_volume_slists(volume, pvol)) 2228c2ecf20Sopenharmony_ci ret = 1; 2238c2ecf20Sopenharmony_ci rcu_read_unlock(); 2248c2ecf20Sopenharmony_ci } 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci afs_put_volume(cell->net, volume, afs_volume_trace_put_query_alias); 2278c2ecf20Sopenharmony_ci afs_put_volume(cell->net, pvol, afs_volume_trace_put_query_alias); 2288c2ecf20Sopenharmony_ci return ret; 2298c2ecf20Sopenharmony_ci} 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci/* 2328c2ecf20Sopenharmony_ci * Query the new cell for volumes we know exist in cells we're already using. 2338c2ecf20Sopenharmony_ci */ 2348c2ecf20Sopenharmony_cistatic int afs_query_for_alias(struct afs_cell *cell, struct key *key) 2358c2ecf20Sopenharmony_ci{ 2368c2ecf20Sopenharmony_ci struct afs_cell *p; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci _enter("%s", cell->name); 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&cell->net->proc_cells_lock) < 0) 2418c2ecf20Sopenharmony_ci return -ERESTARTSYS; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci hlist_for_each_entry(p, &cell->net->proc_cells, proc_link) { 2448c2ecf20Sopenharmony_ci if (p == cell || p->alias_of) 2458c2ecf20Sopenharmony_ci continue; 2468c2ecf20Sopenharmony_ci if (RB_EMPTY_ROOT(&p->volumes)) 2478c2ecf20Sopenharmony_ci continue; 2488c2ecf20Sopenharmony_ci if (p->root_volume) 2498c2ecf20Sopenharmony_ci continue; /* Ignore cells that have a root.cell volume. */ 2508c2ecf20Sopenharmony_ci afs_use_cell(p, afs_cell_trace_use_check_alias); 2518c2ecf20Sopenharmony_ci mutex_unlock(&cell->net->proc_cells_lock); 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci if (afs_query_for_alias_one(cell, key, p) != 0) 2548c2ecf20Sopenharmony_ci goto is_alias; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&cell->net->proc_cells_lock) < 0) { 2578c2ecf20Sopenharmony_ci afs_unuse_cell(cell->net, p, afs_cell_trace_unuse_check_alias); 2588c2ecf20Sopenharmony_ci return -ERESTARTSYS; 2598c2ecf20Sopenharmony_ci } 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci afs_unuse_cell(cell->net, p, afs_cell_trace_unuse_check_alias); 2628c2ecf20Sopenharmony_ci } 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci mutex_unlock(&cell->net->proc_cells_lock); 2658c2ecf20Sopenharmony_ci _leave(" = 0"); 2668c2ecf20Sopenharmony_ci return 0; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ciis_alias: 2698c2ecf20Sopenharmony_ci cell->alias_of = p; /* Transfer our ref */ 2708c2ecf20Sopenharmony_ci return 1; 2718c2ecf20Sopenharmony_ci} 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci/* 2748c2ecf20Sopenharmony_ci * Look up a VLDB record for a volume. 2758c2ecf20Sopenharmony_ci */ 2768c2ecf20Sopenharmony_cistatic char *afs_vl_get_cell_name(struct afs_cell *cell, struct key *key) 2778c2ecf20Sopenharmony_ci{ 2788c2ecf20Sopenharmony_ci struct afs_vl_cursor vc; 2798c2ecf20Sopenharmony_ci char *cell_name = ERR_PTR(-EDESTADDRREQ); 2808c2ecf20Sopenharmony_ci bool skipped = false, not_skipped = false; 2818c2ecf20Sopenharmony_ci int ret; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci if (!afs_begin_vlserver_operation(&vc, cell, key)) 2848c2ecf20Sopenharmony_ci return ERR_PTR(-ERESTARTSYS); 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci while (afs_select_vlserver(&vc)) { 2878c2ecf20Sopenharmony_ci if (!test_bit(AFS_VLSERVER_FL_IS_YFS, &vc.server->flags)) { 2888c2ecf20Sopenharmony_ci vc.ac.error = -EOPNOTSUPP; 2898c2ecf20Sopenharmony_ci skipped = true; 2908c2ecf20Sopenharmony_ci continue; 2918c2ecf20Sopenharmony_ci } 2928c2ecf20Sopenharmony_ci not_skipped = true; 2938c2ecf20Sopenharmony_ci cell_name = afs_yfsvl_get_cell_name(&vc); 2948c2ecf20Sopenharmony_ci } 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci ret = afs_end_vlserver_operation(&vc); 2978c2ecf20Sopenharmony_ci if (skipped && !not_skipped) 2988c2ecf20Sopenharmony_ci ret = -EOPNOTSUPP; 2998c2ecf20Sopenharmony_ci return ret < 0 ? ERR_PTR(ret) : cell_name; 3008c2ecf20Sopenharmony_ci} 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_cistatic int yfs_check_canonical_cell_name(struct afs_cell *cell, struct key *key) 3038c2ecf20Sopenharmony_ci{ 3048c2ecf20Sopenharmony_ci struct afs_cell *master; 3058c2ecf20Sopenharmony_ci char *cell_name; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci cell_name = afs_vl_get_cell_name(cell, key); 3088c2ecf20Sopenharmony_ci if (IS_ERR(cell_name)) 3098c2ecf20Sopenharmony_ci return PTR_ERR(cell_name); 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci if (strcmp(cell_name, cell->name) == 0) { 3128c2ecf20Sopenharmony_ci kfree(cell_name); 3138c2ecf20Sopenharmony_ci return 0; 3148c2ecf20Sopenharmony_ci } 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci master = afs_lookup_cell(cell->net, cell_name, strlen(cell_name), 3178c2ecf20Sopenharmony_ci NULL, false); 3188c2ecf20Sopenharmony_ci kfree(cell_name); 3198c2ecf20Sopenharmony_ci if (IS_ERR(master)) 3208c2ecf20Sopenharmony_ci return PTR_ERR(master); 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci cell->alias_of = master; /* Transfer our ref */ 3238c2ecf20Sopenharmony_ci return 1; 3248c2ecf20Sopenharmony_ci} 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_cistatic int afs_do_cell_detect_alias(struct afs_cell *cell, struct key *key) 3278c2ecf20Sopenharmony_ci{ 3288c2ecf20Sopenharmony_ci struct afs_volume *root_volume; 3298c2ecf20Sopenharmony_ci int ret; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci _enter("%s", cell->name); 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci ret = yfs_check_canonical_cell_name(cell, key); 3348c2ecf20Sopenharmony_ci if (ret != -EOPNOTSUPP) 3358c2ecf20Sopenharmony_ci return ret; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci /* Try and get the root.cell volume for comparison with other cells */ 3388c2ecf20Sopenharmony_ci root_volume = afs_sample_volume(cell, key, "root.cell", 9); 3398c2ecf20Sopenharmony_ci if (!IS_ERR(root_volume)) { 3408c2ecf20Sopenharmony_ci cell->root_volume = root_volume; 3418c2ecf20Sopenharmony_ci return afs_compare_cell_roots(cell); 3428c2ecf20Sopenharmony_ci } 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci if (PTR_ERR(root_volume) != -ENOMEDIUM) 3458c2ecf20Sopenharmony_ci return PTR_ERR(root_volume); 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci /* Okay, this cell doesn't have an root.cell volume. We need to 3488c2ecf20Sopenharmony_ci * locate some other random volume and use that to check. 3498c2ecf20Sopenharmony_ci */ 3508c2ecf20Sopenharmony_ci return afs_query_for_alias(cell, key); 3518c2ecf20Sopenharmony_ci} 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci/* 3548c2ecf20Sopenharmony_ci * Check to see if a new cell is an alias of a cell we already have. At this 3558c2ecf20Sopenharmony_ci * point we have the cell's volume server list. 3568c2ecf20Sopenharmony_ci * 3578c2ecf20Sopenharmony_ci * Returns 0 if we didn't detect an alias, 1 if we found an alias and an error 3588c2ecf20Sopenharmony_ci * if we had problems gathering the data required. In the case the we did 3598c2ecf20Sopenharmony_ci * detect an alias, cell->alias_of is set to point to the assumed master. 3608c2ecf20Sopenharmony_ci */ 3618c2ecf20Sopenharmony_ciint afs_cell_detect_alias(struct afs_cell *cell, struct key *key) 3628c2ecf20Sopenharmony_ci{ 3638c2ecf20Sopenharmony_ci struct afs_net *net = cell->net; 3648c2ecf20Sopenharmony_ci int ret; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&net->cells_alias_lock) < 0) 3678c2ecf20Sopenharmony_ci return -ERESTARTSYS; 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci if (test_bit(AFS_CELL_FL_CHECK_ALIAS, &cell->flags)) { 3708c2ecf20Sopenharmony_ci ret = afs_do_cell_detect_alias(cell, key); 3718c2ecf20Sopenharmony_ci if (ret >= 0) 3728c2ecf20Sopenharmony_ci clear_bit_unlock(AFS_CELL_FL_CHECK_ALIAS, &cell->flags); 3738c2ecf20Sopenharmony_ci } else { 3748c2ecf20Sopenharmony_ci ret = cell->alias_of ? 1 : 0; 3758c2ecf20Sopenharmony_ci } 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci mutex_unlock(&net->cells_alias_lock); 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci if (ret == 1) 3808c2ecf20Sopenharmony_ci pr_notice("kAFS: Cell %s is an alias of %s\n", 3818c2ecf20Sopenharmony_ci cell->name, cell->alias_of->name); 3828c2ecf20Sopenharmony_ci return ret; 3838c2ecf20Sopenharmony_ci} 384