root/fs/afs/volume.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. afs_alloc_volume
  2. afs_vl_lookup_vldb
  3. afs_create_volume
  4. afs_destroy_volume
  5. afs_put_volume
  6. afs_activate_volume
  7. afs_deactivate_volume
  8. afs_update_volume_status
  9. afs_check_volume_status

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /* AFS volume management
   3  *
   4  * Copyright (C) 2002, 2007 Red Hat, Inc. All Rights Reserved.
   5  * Written by David Howells (dhowells@redhat.com)
   6  */
   7 
   8 #include <linux/kernel.h>
   9 #include <linux/slab.h>
  10 #include "internal.h"
  11 
  12 unsigned __read_mostly afs_volume_gc_delay = 10;
  13 unsigned __read_mostly afs_volume_record_life = 60 * 60;
  14 
  15 /*
  16  * Allocate a volume record and load it up from a vldb record.
  17  */
  18 static struct afs_volume *afs_alloc_volume(struct afs_fs_context *params,
  19                                            struct afs_vldb_entry *vldb,
  20                                            unsigned long type_mask)
  21 {
  22         struct afs_server_list *slist;
  23         struct afs_volume *volume;
  24         int ret = -ENOMEM, nr_servers = 0, i;
  25 
  26         for (i = 0; i < vldb->nr_servers; i++)
  27                 if (vldb->fs_mask[i] & type_mask)
  28                         nr_servers++;
  29 
  30         volume = kzalloc(sizeof(struct afs_volume), GFP_KERNEL);
  31         if (!volume)
  32                 goto error_0;
  33 
  34         volume->vid             = vldb->vid[params->type];
  35         volume->update_at       = ktime_get_real_seconds() + afs_volume_record_life;
  36         volume->cell            = afs_get_cell(params->cell);
  37         volume->type            = params->type;
  38         volume->type_force      = params->force;
  39         volume->name_len        = vldb->name_len;
  40 
  41         atomic_set(&volume->usage, 1);
  42         INIT_LIST_HEAD(&volume->proc_link);
  43         rwlock_init(&volume->servers_lock);
  44         rwlock_init(&volume->cb_v_break_lock);
  45         memcpy(volume->name, vldb->name, vldb->name_len + 1);
  46 
  47         slist = afs_alloc_server_list(params->cell, params->key, vldb, type_mask);
  48         if (IS_ERR(slist)) {
  49                 ret = PTR_ERR(slist);
  50                 goto error_1;
  51         }
  52 
  53         refcount_set(&slist->usage, 1);
  54         volume->servers = slist;
  55         return volume;
  56 
  57 error_1:
  58         afs_put_cell(params->net, volume->cell);
  59         kfree(volume);
  60 error_0:
  61         return ERR_PTR(ret);
  62 }
  63 
  64 /*
  65  * Look up a VLDB record for a volume.
  66  */
  67 static struct afs_vldb_entry *afs_vl_lookup_vldb(struct afs_cell *cell,
  68                                                  struct key *key,
  69                                                  const char *volname,
  70                                                  size_t volnamesz)
  71 {
  72         struct afs_vldb_entry *vldb = ERR_PTR(-EDESTADDRREQ);
  73         struct afs_vl_cursor vc;
  74         int ret;
  75 
  76         if (!afs_begin_vlserver_operation(&vc, cell, key))
  77                 return ERR_PTR(-ERESTARTSYS);
  78 
  79         while (afs_select_vlserver(&vc)) {
  80                 vldb = afs_vl_get_entry_by_name_u(&vc, volname, volnamesz);
  81         }
  82 
  83         ret = afs_end_vlserver_operation(&vc);
  84         return ret < 0 ? ERR_PTR(ret) : vldb;
  85 }
  86 
  87 /*
  88  * Look up a volume in the VL server and create a candidate volume record for
  89  * it.
  90  *
  91  * The volume name can be one of the following:
  92  *      "%[cell:]volume[.]"             R/W volume
  93  *      "#[cell:]volume[.]"             R/O or R/W volume (rwparent=0),
  94  *                                       or R/W (rwparent=1) volume
  95  *      "%[cell:]volume.readonly"       R/O volume
  96  *      "#[cell:]volume.readonly"       R/O volume
  97  *      "%[cell:]volume.backup"         Backup volume
  98  *      "#[cell:]volume.backup"         Backup volume
  99  *
 100  * The cell name is optional, and defaults to the current cell.
 101  *
 102  * See "The Rules of Mount Point Traversal" in Chapter 5 of the AFS SysAdmin
 103  * Guide
 104  * - Rule 1: Explicit type suffix forces access of that type or nothing
 105  *           (no suffix, then use Rule 2 & 3)
 106  * - Rule 2: If parent volume is R/O, then mount R/O volume by preference, R/W
 107  *           if not available
 108  * - Rule 3: If parent volume is R/W, then only mount R/W volume unless
 109  *           explicitly told otherwise
 110  */
 111 struct afs_volume *afs_create_volume(struct afs_fs_context *params)
 112 {
 113         struct afs_vldb_entry *vldb;
 114         struct afs_volume *volume;
 115         unsigned long type_mask = 1UL << params->type;
 116 
 117         vldb = afs_vl_lookup_vldb(params->cell, params->key,
 118                                   params->volname, params->volnamesz);
 119         if (IS_ERR(vldb))
 120                 return ERR_CAST(vldb);
 121 
 122         if (test_bit(AFS_VLDB_QUERY_ERROR, &vldb->flags)) {
 123                 volume = ERR_PTR(vldb->error);
 124                 goto error;
 125         }
 126 
 127         /* Make the final decision on the type we want */
 128         volume = ERR_PTR(-ENOMEDIUM);
 129         if (params->force) {
 130                 if (!(vldb->flags & type_mask))
 131                         goto error;
 132         } else if (test_bit(AFS_VLDB_HAS_RO, &vldb->flags)) {
 133                 params->type = AFSVL_ROVOL;
 134         } else if (test_bit(AFS_VLDB_HAS_RW, &vldb->flags)) {
 135                 params->type = AFSVL_RWVOL;
 136         } else {
 137                 goto error;
 138         }
 139 
 140         type_mask = 1UL << params->type;
 141         volume = afs_alloc_volume(params, vldb, type_mask);
 142 
 143 error:
 144         kfree(vldb);
 145         return volume;
 146 }
 147 
 148 /*
 149  * Destroy a volume record
 150  */
 151 static void afs_destroy_volume(struct afs_net *net, struct afs_volume *volume)
 152 {
 153         _enter("%p", volume);
 154 
 155 #ifdef CONFIG_AFS_FSCACHE
 156         ASSERTCMP(volume->cache, ==, NULL);
 157 #endif
 158 
 159         afs_put_serverlist(net, volume->servers);
 160         afs_put_cell(net, volume->cell);
 161         kfree(volume);
 162 
 163         _leave(" [destroyed]");
 164 }
 165 
 166 /*
 167  * Drop a reference on a volume record.
 168  */
 169 void afs_put_volume(struct afs_cell *cell, struct afs_volume *volume)
 170 {
 171         if (volume) {
 172                 _enter("%s", volume->name);
 173 
 174                 if (atomic_dec_and_test(&volume->usage))
 175                         afs_destroy_volume(cell->net, volume);
 176         }
 177 }
 178 
 179 /*
 180  * Activate a volume.
 181  */
 182 void afs_activate_volume(struct afs_volume *volume)
 183 {
 184 #ifdef CONFIG_AFS_FSCACHE
 185         volume->cache = fscache_acquire_cookie(volume->cell->cache,
 186                                                &afs_volume_cache_index_def,
 187                                                &volume->vid, sizeof(volume->vid),
 188                                                NULL, 0,
 189                                                volume, 0, true);
 190 #endif
 191 
 192         write_lock(&volume->cell->proc_lock);
 193         list_add_tail(&volume->proc_link, &volume->cell->proc_volumes);
 194         write_unlock(&volume->cell->proc_lock);
 195 }
 196 
 197 /*
 198  * Deactivate a volume.
 199  */
 200 void afs_deactivate_volume(struct afs_volume *volume)
 201 {
 202         _enter("%s", volume->name);
 203 
 204         write_lock(&volume->cell->proc_lock);
 205         list_del_init(&volume->proc_link);
 206         write_unlock(&volume->cell->proc_lock);
 207 
 208 #ifdef CONFIG_AFS_FSCACHE
 209         fscache_relinquish_cookie(volume->cache, NULL,
 210                                   test_bit(AFS_VOLUME_DELETED, &volume->flags));
 211         volume->cache = NULL;
 212 #endif
 213 
 214         _leave("");
 215 }
 216 
 217 /*
 218  * Query the VL service to update the volume status.
 219  */
 220 static int afs_update_volume_status(struct afs_volume *volume, struct key *key)
 221 {
 222         struct afs_server_list *new, *old, *discard;
 223         struct afs_vldb_entry *vldb;
 224         char idbuf[16];
 225         int ret, idsz;
 226 
 227         _enter("");
 228 
 229         /* We look up an ID by passing it as a decimal string in the
 230          * operation's name parameter.
 231          */
 232         idsz = sprintf(idbuf, "%llu", volume->vid);
 233 
 234         vldb = afs_vl_lookup_vldb(volume->cell, key, idbuf, idsz);
 235         if (IS_ERR(vldb)) {
 236                 ret = PTR_ERR(vldb);
 237                 goto error;
 238         }
 239 
 240         /* See if the volume got renamed. */
 241         if (vldb->name_len != volume->name_len ||
 242             memcmp(vldb->name, volume->name, vldb->name_len) != 0) {
 243                 /* TODO: Use RCU'd string. */
 244                 memcpy(volume->name, vldb->name, AFS_MAXVOLNAME);
 245                 volume->name_len = vldb->name_len;
 246         }
 247 
 248         /* See if the volume's server list got updated. */
 249         new = afs_alloc_server_list(volume->cell, key,
 250                                     vldb, (1 << volume->type));
 251         if (IS_ERR(new)) {
 252                 ret = PTR_ERR(new);
 253                 goto error_vldb;
 254         }
 255 
 256         write_lock(&volume->servers_lock);
 257 
 258         discard = new;
 259         old = volume->servers;
 260         if (afs_annotate_server_list(new, old)) {
 261                 new->seq = volume->servers_seq + 1;
 262                 volume->servers = new;
 263                 smp_wmb();
 264                 volume->servers_seq++;
 265                 discard = old;
 266         }
 267 
 268         volume->update_at = ktime_get_real_seconds() + afs_volume_record_life;
 269         clear_bit(AFS_VOLUME_NEEDS_UPDATE, &volume->flags);
 270         write_unlock(&volume->servers_lock);
 271         ret = 0;
 272 
 273         afs_put_serverlist(volume->cell->net, discard);
 274 error_vldb:
 275         kfree(vldb);
 276 error:
 277         _leave(" = %d", ret);
 278         return ret;
 279 }
 280 
 281 /*
 282  * Make sure the volume record is up to date.
 283  */
 284 int afs_check_volume_status(struct afs_volume *volume, struct afs_fs_cursor *fc)
 285 {
 286         time64_t now = ktime_get_real_seconds();
 287         int ret, retries = 0;
 288 
 289         _enter("");
 290 
 291         if (volume->update_at <= now)
 292                 set_bit(AFS_VOLUME_NEEDS_UPDATE, &volume->flags);
 293 
 294 retry:
 295         if (!test_bit(AFS_VOLUME_NEEDS_UPDATE, &volume->flags) &&
 296             !test_bit(AFS_VOLUME_WAIT, &volume->flags)) {
 297                 _leave(" = 0");
 298                 return 0;
 299         }
 300 
 301         if (!test_and_set_bit_lock(AFS_VOLUME_UPDATING, &volume->flags)) {
 302                 ret = afs_update_volume_status(volume, fc->key);
 303                 clear_bit_unlock(AFS_VOLUME_WAIT, &volume->flags);
 304                 clear_bit_unlock(AFS_VOLUME_UPDATING, &volume->flags);
 305                 wake_up_bit(&volume->flags, AFS_VOLUME_WAIT);
 306                 _leave(" = %d", ret);
 307                 return ret;
 308         }
 309 
 310         if (!test_bit(AFS_VOLUME_WAIT, &volume->flags)) {
 311                 _leave(" = 0 [no wait]");
 312                 return 0;
 313         }
 314 
 315         ret = wait_on_bit(&volume->flags, AFS_VOLUME_WAIT,
 316                           (fc->flags & AFS_FS_CURSOR_INTR) ?
 317                           TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE);
 318         if (ret == -ERESTARTSYS) {
 319                 _leave(" = %d", ret);
 320                 return ret;
 321         }
 322 
 323         retries++;
 324         if (retries == 4) {
 325                 _leave(" = -ESTALE");
 326                 return -ESTALE;
 327         }
 328         goto retry;
 329 }

/* [<][>][^][v][top][bottom][index][help] */