18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* AFS volume management 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 2002, 2007 Red Hat, Inc. All Rights Reserved. 58c2ecf20Sopenharmony_ci * Written by David Howells (dhowells@redhat.com) 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/kernel.h> 98c2ecf20Sopenharmony_ci#include <linux/slab.h> 108c2ecf20Sopenharmony_ci#include "internal.h" 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ciunsigned __read_mostly afs_volume_gc_delay = 10; 138c2ecf20Sopenharmony_ciunsigned __read_mostly afs_volume_record_life = 60 * 60; 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci/* 168c2ecf20Sopenharmony_ci * Insert a volume into a cell. If there's an existing volume record, that is 178c2ecf20Sopenharmony_ci * returned instead with a ref held. 188c2ecf20Sopenharmony_ci */ 198c2ecf20Sopenharmony_cistatic struct afs_volume *afs_insert_volume_into_cell(struct afs_cell *cell, 208c2ecf20Sopenharmony_ci struct afs_volume *volume) 218c2ecf20Sopenharmony_ci{ 228c2ecf20Sopenharmony_ci struct afs_volume *p; 238c2ecf20Sopenharmony_ci struct rb_node *parent = NULL, **pp; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci write_seqlock(&cell->volume_lock); 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci pp = &cell->volumes.rb_node; 288c2ecf20Sopenharmony_ci while (*pp) { 298c2ecf20Sopenharmony_ci parent = *pp; 308c2ecf20Sopenharmony_ci p = rb_entry(parent, struct afs_volume, cell_node); 318c2ecf20Sopenharmony_ci if (p->vid < volume->vid) { 328c2ecf20Sopenharmony_ci pp = &(*pp)->rb_left; 338c2ecf20Sopenharmony_ci } else if (p->vid > volume->vid) { 348c2ecf20Sopenharmony_ci pp = &(*pp)->rb_right; 358c2ecf20Sopenharmony_ci } else { 368c2ecf20Sopenharmony_ci volume = afs_get_volume(p, afs_volume_trace_get_cell_insert); 378c2ecf20Sopenharmony_ci goto found; 388c2ecf20Sopenharmony_ci } 398c2ecf20Sopenharmony_ci } 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci rb_link_node_rcu(&volume->cell_node, parent, pp); 428c2ecf20Sopenharmony_ci rb_insert_color(&volume->cell_node, &cell->volumes); 438c2ecf20Sopenharmony_ci hlist_add_head_rcu(&volume->proc_link, &cell->proc_volumes); 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cifound: 468c2ecf20Sopenharmony_ci write_sequnlock(&cell->volume_lock); 478c2ecf20Sopenharmony_ci return volume; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci} 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistatic void afs_remove_volume_from_cell(struct afs_volume *volume) 528c2ecf20Sopenharmony_ci{ 538c2ecf20Sopenharmony_ci struct afs_cell *cell = volume->cell; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci if (!hlist_unhashed(&volume->proc_link)) { 568c2ecf20Sopenharmony_ci trace_afs_volume(volume->vid, atomic_read(&volume->usage), 578c2ecf20Sopenharmony_ci afs_volume_trace_remove); 588c2ecf20Sopenharmony_ci write_seqlock(&cell->volume_lock); 598c2ecf20Sopenharmony_ci hlist_del_rcu(&volume->proc_link); 608c2ecf20Sopenharmony_ci rb_erase(&volume->cell_node, &cell->volumes); 618c2ecf20Sopenharmony_ci write_sequnlock(&cell->volume_lock); 628c2ecf20Sopenharmony_ci } 638c2ecf20Sopenharmony_ci} 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci/* 668c2ecf20Sopenharmony_ci * Allocate a volume record and load it up from a vldb record. 678c2ecf20Sopenharmony_ci */ 688c2ecf20Sopenharmony_cistatic struct afs_volume *afs_alloc_volume(struct afs_fs_context *params, 698c2ecf20Sopenharmony_ci struct afs_vldb_entry *vldb, 708c2ecf20Sopenharmony_ci unsigned long type_mask) 718c2ecf20Sopenharmony_ci{ 728c2ecf20Sopenharmony_ci struct afs_server_list *slist; 738c2ecf20Sopenharmony_ci struct afs_volume *volume; 748c2ecf20Sopenharmony_ci int ret = -ENOMEM, nr_servers = 0, i; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci for (i = 0; i < vldb->nr_servers; i++) 778c2ecf20Sopenharmony_ci if (vldb->fs_mask[i] & type_mask) 788c2ecf20Sopenharmony_ci nr_servers++; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci volume = kzalloc(sizeof(struct afs_volume), GFP_KERNEL); 818c2ecf20Sopenharmony_ci if (!volume) 828c2ecf20Sopenharmony_ci goto error_0; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci volume->vid = vldb->vid[params->type]; 858c2ecf20Sopenharmony_ci volume->update_at = ktime_get_real_seconds() + afs_volume_record_life; 868c2ecf20Sopenharmony_ci volume->cell = afs_get_cell(params->cell, afs_cell_trace_get_vol); 878c2ecf20Sopenharmony_ci volume->type = params->type; 888c2ecf20Sopenharmony_ci volume->type_force = params->force; 898c2ecf20Sopenharmony_ci volume->name_len = vldb->name_len; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci atomic_set(&volume->usage, 1); 928c2ecf20Sopenharmony_ci INIT_HLIST_NODE(&volume->proc_link); 938c2ecf20Sopenharmony_ci rwlock_init(&volume->servers_lock); 948c2ecf20Sopenharmony_ci rwlock_init(&volume->cb_v_break_lock); 958c2ecf20Sopenharmony_ci memcpy(volume->name, vldb->name, vldb->name_len + 1); 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci slist = afs_alloc_server_list(params->cell, params->key, vldb, type_mask); 988c2ecf20Sopenharmony_ci if (IS_ERR(slist)) { 998c2ecf20Sopenharmony_ci ret = PTR_ERR(slist); 1008c2ecf20Sopenharmony_ci goto error_1; 1018c2ecf20Sopenharmony_ci } 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci refcount_set(&slist->usage, 1); 1048c2ecf20Sopenharmony_ci rcu_assign_pointer(volume->servers, slist); 1058c2ecf20Sopenharmony_ci trace_afs_volume(volume->vid, 1, afs_volume_trace_alloc); 1068c2ecf20Sopenharmony_ci return volume; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_cierror_1: 1098c2ecf20Sopenharmony_ci afs_put_cell(volume->cell, afs_cell_trace_put_vol); 1108c2ecf20Sopenharmony_ci kfree(volume); 1118c2ecf20Sopenharmony_cierror_0: 1128c2ecf20Sopenharmony_ci return ERR_PTR(ret); 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci/* 1168c2ecf20Sopenharmony_ci * Look up or allocate a volume record. 1178c2ecf20Sopenharmony_ci */ 1188c2ecf20Sopenharmony_cistatic struct afs_volume *afs_lookup_volume(struct afs_fs_context *params, 1198c2ecf20Sopenharmony_ci struct afs_vldb_entry *vldb, 1208c2ecf20Sopenharmony_ci unsigned long type_mask) 1218c2ecf20Sopenharmony_ci{ 1228c2ecf20Sopenharmony_ci struct afs_volume *candidate, *volume; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci candidate = afs_alloc_volume(params, vldb, type_mask); 1258c2ecf20Sopenharmony_ci if (IS_ERR(candidate)) 1268c2ecf20Sopenharmony_ci return candidate; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci volume = afs_insert_volume_into_cell(params->cell, candidate); 1298c2ecf20Sopenharmony_ci if (volume != candidate) 1308c2ecf20Sopenharmony_ci afs_put_volume(params->net, candidate, afs_volume_trace_put_cell_dup); 1318c2ecf20Sopenharmony_ci return volume; 1328c2ecf20Sopenharmony_ci} 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci/* 1358c2ecf20Sopenharmony_ci * Look up a VLDB record for a volume. 1368c2ecf20Sopenharmony_ci */ 1378c2ecf20Sopenharmony_cistatic struct afs_vldb_entry *afs_vl_lookup_vldb(struct afs_cell *cell, 1388c2ecf20Sopenharmony_ci struct key *key, 1398c2ecf20Sopenharmony_ci const char *volname, 1408c2ecf20Sopenharmony_ci size_t volnamesz) 1418c2ecf20Sopenharmony_ci{ 1428c2ecf20Sopenharmony_ci struct afs_vldb_entry *vldb = ERR_PTR(-EDESTADDRREQ); 1438c2ecf20Sopenharmony_ci struct afs_vl_cursor vc; 1448c2ecf20Sopenharmony_ci int ret; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci if (!afs_begin_vlserver_operation(&vc, cell, key)) 1478c2ecf20Sopenharmony_ci return ERR_PTR(-ERESTARTSYS); 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci while (afs_select_vlserver(&vc)) { 1508c2ecf20Sopenharmony_ci vldb = afs_vl_get_entry_by_name_u(&vc, volname, volnamesz); 1518c2ecf20Sopenharmony_ci } 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci ret = afs_end_vlserver_operation(&vc); 1548c2ecf20Sopenharmony_ci return ret < 0 ? ERR_PTR(ret) : vldb; 1558c2ecf20Sopenharmony_ci} 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci/* 1588c2ecf20Sopenharmony_ci * Look up a volume in the VL server and create a candidate volume record for 1598c2ecf20Sopenharmony_ci * it. 1608c2ecf20Sopenharmony_ci * 1618c2ecf20Sopenharmony_ci * The volume name can be one of the following: 1628c2ecf20Sopenharmony_ci * "%[cell:]volume[.]" R/W volume 1638c2ecf20Sopenharmony_ci * "#[cell:]volume[.]" R/O or R/W volume (rwparent=0), 1648c2ecf20Sopenharmony_ci * or R/W (rwparent=1) volume 1658c2ecf20Sopenharmony_ci * "%[cell:]volume.readonly" R/O volume 1668c2ecf20Sopenharmony_ci * "#[cell:]volume.readonly" R/O volume 1678c2ecf20Sopenharmony_ci * "%[cell:]volume.backup" Backup volume 1688c2ecf20Sopenharmony_ci * "#[cell:]volume.backup" Backup volume 1698c2ecf20Sopenharmony_ci * 1708c2ecf20Sopenharmony_ci * The cell name is optional, and defaults to the current cell. 1718c2ecf20Sopenharmony_ci * 1728c2ecf20Sopenharmony_ci * See "The Rules of Mount Point Traversal" in Chapter 5 of the AFS SysAdmin 1738c2ecf20Sopenharmony_ci * Guide 1748c2ecf20Sopenharmony_ci * - Rule 1: Explicit type suffix forces access of that type or nothing 1758c2ecf20Sopenharmony_ci * (no suffix, then use Rule 2 & 3) 1768c2ecf20Sopenharmony_ci * - Rule 2: If parent volume is R/O, then mount R/O volume by preference, R/W 1778c2ecf20Sopenharmony_ci * if not available 1788c2ecf20Sopenharmony_ci * - Rule 3: If parent volume is R/W, then only mount R/W volume unless 1798c2ecf20Sopenharmony_ci * explicitly told otherwise 1808c2ecf20Sopenharmony_ci */ 1818c2ecf20Sopenharmony_cistruct afs_volume *afs_create_volume(struct afs_fs_context *params) 1828c2ecf20Sopenharmony_ci{ 1838c2ecf20Sopenharmony_ci struct afs_vldb_entry *vldb; 1848c2ecf20Sopenharmony_ci struct afs_volume *volume; 1858c2ecf20Sopenharmony_ci unsigned long type_mask = 1UL << params->type; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci vldb = afs_vl_lookup_vldb(params->cell, params->key, 1888c2ecf20Sopenharmony_ci params->volname, params->volnamesz); 1898c2ecf20Sopenharmony_ci if (IS_ERR(vldb)) 1908c2ecf20Sopenharmony_ci return ERR_CAST(vldb); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci if (test_bit(AFS_VLDB_QUERY_ERROR, &vldb->flags)) { 1938c2ecf20Sopenharmony_ci volume = ERR_PTR(vldb->error); 1948c2ecf20Sopenharmony_ci goto error; 1958c2ecf20Sopenharmony_ci } 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci /* Make the final decision on the type we want */ 1988c2ecf20Sopenharmony_ci volume = ERR_PTR(-ENOMEDIUM); 1998c2ecf20Sopenharmony_ci if (params->force) { 2008c2ecf20Sopenharmony_ci if (!(vldb->flags & type_mask)) 2018c2ecf20Sopenharmony_ci goto error; 2028c2ecf20Sopenharmony_ci } else if (test_bit(AFS_VLDB_HAS_RO, &vldb->flags)) { 2038c2ecf20Sopenharmony_ci params->type = AFSVL_ROVOL; 2048c2ecf20Sopenharmony_ci } else if (test_bit(AFS_VLDB_HAS_RW, &vldb->flags)) { 2058c2ecf20Sopenharmony_ci params->type = AFSVL_RWVOL; 2068c2ecf20Sopenharmony_ci } else { 2078c2ecf20Sopenharmony_ci goto error; 2088c2ecf20Sopenharmony_ci } 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci type_mask = 1UL << params->type; 2118c2ecf20Sopenharmony_ci volume = afs_lookup_volume(params, vldb, type_mask); 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_cierror: 2148c2ecf20Sopenharmony_ci kfree(vldb); 2158c2ecf20Sopenharmony_ci return volume; 2168c2ecf20Sopenharmony_ci} 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci/* 2198c2ecf20Sopenharmony_ci * Destroy a volume record 2208c2ecf20Sopenharmony_ci */ 2218c2ecf20Sopenharmony_cistatic void afs_destroy_volume(struct afs_net *net, struct afs_volume *volume) 2228c2ecf20Sopenharmony_ci{ 2238c2ecf20Sopenharmony_ci _enter("%p", volume); 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci#ifdef CONFIG_AFS_FSCACHE 2268c2ecf20Sopenharmony_ci ASSERTCMP(volume->cache, ==, NULL); 2278c2ecf20Sopenharmony_ci#endif 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci afs_remove_volume_from_cell(volume); 2308c2ecf20Sopenharmony_ci afs_put_serverlist(net, rcu_access_pointer(volume->servers)); 2318c2ecf20Sopenharmony_ci afs_put_cell(volume->cell, afs_cell_trace_put_vol); 2328c2ecf20Sopenharmony_ci trace_afs_volume(volume->vid, atomic_read(&volume->usage), 2338c2ecf20Sopenharmony_ci afs_volume_trace_free); 2348c2ecf20Sopenharmony_ci kfree_rcu(volume, rcu); 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci _leave(" [destroyed]"); 2378c2ecf20Sopenharmony_ci} 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci/* 2408c2ecf20Sopenharmony_ci * Get a reference on a volume record. 2418c2ecf20Sopenharmony_ci */ 2428c2ecf20Sopenharmony_cistruct afs_volume *afs_get_volume(struct afs_volume *volume, 2438c2ecf20Sopenharmony_ci enum afs_volume_trace reason) 2448c2ecf20Sopenharmony_ci{ 2458c2ecf20Sopenharmony_ci if (volume) { 2468c2ecf20Sopenharmony_ci int u = atomic_inc_return(&volume->usage); 2478c2ecf20Sopenharmony_ci trace_afs_volume(volume->vid, u, reason); 2488c2ecf20Sopenharmony_ci } 2498c2ecf20Sopenharmony_ci return volume; 2508c2ecf20Sopenharmony_ci} 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci/* 2548c2ecf20Sopenharmony_ci * Drop a reference on a volume record. 2558c2ecf20Sopenharmony_ci */ 2568c2ecf20Sopenharmony_civoid afs_put_volume(struct afs_net *net, struct afs_volume *volume, 2578c2ecf20Sopenharmony_ci enum afs_volume_trace reason) 2588c2ecf20Sopenharmony_ci{ 2598c2ecf20Sopenharmony_ci if (volume) { 2608c2ecf20Sopenharmony_ci afs_volid_t vid = volume->vid; 2618c2ecf20Sopenharmony_ci int u = atomic_dec_return(&volume->usage); 2628c2ecf20Sopenharmony_ci trace_afs_volume(vid, u, reason); 2638c2ecf20Sopenharmony_ci if (u == 0) 2648c2ecf20Sopenharmony_ci afs_destroy_volume(net, volume); 2658c2ecf20Sopenharmony_ci } 2668c2ecf20Sopenharmony_ci} 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci/* 2698c2ecf20Sopenharmony_ci * Activate a volume. 2708c2ecf20Sopenharmony_ci */ 2718c2ecf20Sopenharmony_civoid afs_activate_volume(struct afs_volume *volume) 2728c2ecf20Sopenharmony_ci{ 2738c2ecf20Sopenharmony_ci#ifdef CONFIG_AFS_FSCACHE 2748c2ecf20Sopenharmony_ci volume->cache = fscache_acquire_cookie(volume->cell->cache, 2758c2ecf20Sopenharmony_ci &afs_volume_cache_index_def, 2768c2ecf20Sopenharmony_ci &volume->vid, sizeof(volume->vid), 2778c2ecf20Sopenharmony_ci NULL, 0, 2788c2ecf20Sopenharmony_ci volume, 0, true); 2798c2ecf20Sopenharmony_ci#endif 2808c2ecf20Sopenharmony_ci} 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci/* 2838c2ecf20Sopenharmony_ci * Deactivate a volume. 2848c2ecf20Sopenharmony_ci */ 2858c2ecf20Sopenharmony_civoid afs_deactivate_volume(struct afs_volume *volume) 2868c2ecf20Sopenharmony_ci{ 2878c2ecf20Sopenharmony_ci _enter("%s", volume->name); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci#ifdef CONFIG_AFS_FSCACHE 2908c2ecf20Sopenharmony_ci fscache_relinquish_cookie(volume->cache, NULL, 2918c2ecf20Sopenharmony_ci test_bit(AFS_VOLUME_DELETED, &volume->flags)); 2928c2ecf20Sopenharmony_ci volume->cache = NULL; 2938c2ecf20Sopenharmony_ci#endif 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci _leave(""); 2968c2ecf20Sopenharmony_ci} 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci/* 2998c2ecf20Sopenharmony_ci * Query the VL service to update the volume status. 3008c2ecf20Sopenharmony_ci */ 3018c2ecf20Sopenharmony_cistatic int afs_update_volume_status(struct afs_volume *volume, struct key *key) 3028c2ecf20Sopenharmony_ci{ 3038c2ecf20Sopenharmony_ci struct afs_server_list *new, *old, *discard; 3048c2ecf20Sopenharmony_ci struct afs_vldb_entry *vldb; 3058c2ecf20Sopenharmony_ci char idbuf[16]; 3068c2ecf20Sopenharmony_ci int ret, idsz; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci _enter(""); 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci /* We look up an ID by passing it as a decimal string in the 3118c2ecf20Sopenharmony_ci * operation's name parameter. 3128c2ecf20Sopenharmony_ci */ 3138c2ecf20Sopenharmony_ci idsz = sprintf(idbuf, "%llu", volume->vid); 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci vldb = afs_vl_lookup_vldb(volume->cell, key, idbuf, idsz); 3168c2ecf20Sopenharmony_ci if (IS_ERR(vldb)) { 3178c2ecf20Sopenharmony_ci ret = PTR_ERR(vldb); 3188c2ecf20Sopenharmony_ci goto error; 3198c2ecf20Sopenharmony_ci } 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci /* See if the volume got renamed. */ 3228c2ecf20Sopenharmony_ci if (vldb->name_len != volume->name_len || 3238c2ecf20Sopenharmony_ci memcmp(vldb->name, volume->name, vldb->name_len) != 0) { 3248c2ecf20Sopenharmony_ci /* TODO: Use RCU'd string. */ 3258c2ecf20Sopenharmony_ci memcpy(volume->name, vldb->name, AFS_MAXVOLNAME); 3268c2ecf20Sopenharmony_ci volume->name_len = vldb->name_len; 3278c2ecf20Sopenharmony_ci } 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci /* See if the volume's server list got updated. */ 3308c2ecf20Sopenharmony_ci new = afs_alloc_server_list(volume->cell, key, 3318c2ecf20Sopenharmony_ci vldb, (1 << volume->type)); 3328c2ecf20Sopenharmony_ci if (IS_ERR(new)) { 3338c2ecf20Sopenharmony_ci ret = PTR_ERR(new); 3348c2ecf20Sopenharmony_ci goto error_vldb; 3358c2ecf20Sopenharmony_ci } 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci write_lock(&volume->servers_lock); 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci discard = new; 3408c2ecf20Sopenharmony_ci old = rcu_dereference_protected(volume->servers, 3418c2ecf20Sopenharmony_ci lockdep_is_held(&volume->servers_lock)); 3428c2ecf20Sopenharmony_ci if (afs_annotate_server_list(new, old)) { 3438c2ecf20Sopenharmony_ci new->seq = volume->servers_seq + 1; 3448c2ecf20Sopenharmony_ci rcu_assign_pointer(volume->servers, new); 3458c2ecf20Sopenharmony_ci smp_wmb(); 3468c2ecf20Sopenharmony_ci volume->servers_seq++; 3478c2ecf20Sopenharmony_ci discard = old; 3488c2ecf20Sopenharmony_ci } 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci volume->update_at = ktime_get_real_seconds() + afs_volume_record_life; 3518c2ecf20Sopenharmony_ci write_unlock(&volume->servers_lock); 3528c2ecf20Sopenharmony_ci ret = 0; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci afs_put_serverlist(volume->cell->net, discard); 3558c2ecf20Sopenharmony_cierror_vldb: 3568c2ecf20Sopenharmony_ci kfree(vldb); 3578c2ecf20Sopenharmony_cierror: 3588c2ecf20Sopenharmony_ci _leave(" = %d", ret); 3598c2ecf20Sopenharmony_ci return ret; 3608c2ecf20Sopenharmony_ci} 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci/* 3638c2ecf20Sopenharmony_ci * Make sure the volume record is up to date. 3648c2ecf20Sopenharmony_ci */ 3658c2ecf20Sopenharmony_ciint afs_check_volume_status(struct afs_volume *volume, struct afs_operation *op) 3668c2ecf20Sopenharmony_ci{ 3678c2ecf20Sopenharmony_ci int ret, retries = 0; 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci _enter(""); 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ciretry: 3728c2ecf20Sopenharmony_ci if (test_bit(AFS_VOLUME_WAIT, &volume->flags)) 3738c2ecf20Sopenharmony_ci goto wait; 3748c2ecf20Sopenharmony_ci if (volume->update_at <= ktime_get_real_seconds() || 3758c2ecf20Sopenharmony_ci test_bit(AFS_VOLUME_NEEDS_UPDATE, &volume->flags)) 3768c2ecf20Sopenharmony_ci goto update; 3778c2ecf20Sopenharmony_ci _leave(" = 0"); 3788c2ecf20Sopenharmony_ci return 0; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ciupdate: 3818c2ecf20Sopenharmony_ci if (!test_and_set_bit_lock(AFS_VOLUME_UPDATING, &volume->flags)) { 3828c2ecf20Sopenharmony_ci clear_bit(AFS_VOLUME_NEEDS_UPDATE, &volume->flags); 3838c2ecf20Sopenharmony_ci ret = afs_update_volume_status(volume, op->key); 3848c2ecf20Sopenharmony_ci if (ret < 0) 3858c2ecf20Sopenharmony_ci set_bit(AFS_VOLUME_NEEDS_UPDATE, &volume->flags); 3868c2ecf20Sopenharmony_ci clear_bit_unlock(AFS_VOLUME_WAIT, &volume->flags); 3878c2ecf20Sopenharmony_ci clear_bit_unlock(AFS_VOLUME_UPDATING, &volume->flags); 3888c2ecf20Sopenharmony_ci wake_up_bit(&volume->flags, AFS_VOLUME_WAIT); 3898c2ecf20Sopenharmony_ci _leave(" = %d", ret); 3908c2ecf20Sopenharmony_ci return ret; 3918c2ecf20Sopenharmony_ci } 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ciwait: 3948c2ecf20Sopenharmony_ci if (!test_bit(AFS_VOLUME_WAIT, &volume->flags)) { 3958c2ecf20Sopenharmony_ci _leave(" = 0 [no wait]"); 3968c2ecf20Sopenharmony_ci return 0; 3978c2ecf20Sopenharmony_ci } 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci ret = wait_on_bit(&volume->flags, AFS_VOLUME_WAIT, 4008c2ecf20Sopenharmony_ci (op->flags & AFS_OPERATION_UNINTR) ? 4018c2ecf20Sopenharmony_ci TASK_UNINTERRUPTIBLE : TASK_INTERRUPTIBLE); 4028c2ecf20Sopenharmony_ci if (ret == -ERESTARTSYS) { 4038c2ecf20Sopenharmony_ci _leave(" = %d", ret); 4048c2ecf20Sopenharmony_ci return ret; 4058c2ecf20Sopenharmony_ci } 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci retries++; 4088c2ecf20Sopenharmony_ci if (retries == 4) { 4098c2ecf20Sopenharmony_ci _leave(" = -ESTALE"); 4108c2ecf20Sopenharmony_ci return -ESTALE; 4118c2ecf20Sopenharmony_ci } 4128c2ecf20Sopenharmony_ci goto retry; 4138c2ecf20Sopenharmony_ci} 414