mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-05 18:41:58 +09:00
afs: Make it possible to find the volumes that are using a server
[ Upstream commit ca0e79a46097d54e4af46c67c852479d97af35bb ] Make it possible to find the afs_volume structs that are using an afs_server struct to aid in breaking volume callbacks. The way this is done is that each afs_volume already has an array of afs_server_entry records that point to the servers where that volume might be found. An afs_volume backpointer and a list node is added to each entry and each entry is then added to an RCU-traversable list on the afs_server to which it points. Signed-off-by: David Howells <dhowells@redhat.com> cc: Marc Dionne <marc.dionne@auristor.com> cc: linux-afs@lists.infradead.org Stable-dep-of: add117e48df4 ("afs: Fix the server_list to unuse a displaced server rather than putting it") Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
916e5a561e
commit
1dac4025eb
@@ -161,6 +161,7 @@ static struct afs_cell *afs_alloc_cell(struct afs_net *net,
|
|||||||
refcount_set(&cell->ref, 1);
|
refcount_set(&cell->ref, 1);
|
||||||
atomic_set(&cell->active, 0);
|
atomic_set(&cell->active, 0);
|
||||||
INIT_WORK(&cell->manager, afs_manage_cell_work);
|
INIT_WORK(&cell->manager, afs_manage_cell_work);
|
||||||
|
spin_lock_init(&cell->vs_lock);
|
||||||
cell->volumes = RB_ROOT;
|
cell->volumes = RB_ROOT;
|
||||||
INIT_HLIST_HEAD(&cell->proc_volumes);
|
INIT_HLIST_HEAD(&cell->proc_volumes);
|
||||||
seqlock_init(&cell->volume_lock);
|
seqlock_init(&cell->volume_lock);
|
||||||
|
|||||||
@@ -378,6 +378,7 @@ struct afs_cell {
|
|||||||
unsigned int debug_id;
|
unsigned int debug_id;
|
||||||
|
|
||||||
/* The volumes belonging to this cell */
|
/* The volumes belonging to this cell */
|
||||||
|
spinlock_t vs_lock; /* Lock for server->volumes */
|
||||||
struct rb_root volumes; /* Tree of volumes on this server */
|
struct rb_root volumes; /* Tree of volumes on this server */
|
||||||
struct hlist_head proc_volumes; /* procfs volume list */
|
struct hlist_head proc_volumes; /* procfs volume list */
|
||||||
seqlock_t volume_lock; /* For volumes */
|
seqlock_t volume_lock; /* For volumes */
|
||||||
@@ -501,6 +502,7 @@ struct afs_server {
|
|||||||
struct hlist_node addr4_link; /* Link in net->fs_addresses4 */
|
struct hlist_node addr4_link; /* Link in net->fs_addresses4 */
|
||||||
struct hlist_node addr6_link; /* Link in net->fs_addresses6 */
|
struct hlist_node addr6_link; /* Link in net->fs_addresses6 */
|
||||||
struct hlist_node proc_link; /* Link in net->fs_proc */
|
struct hlist_node proc_link; /* Link in net->fs_proc */
|
||||||
|
struct list_head volumes; /* RCU list of afs_server_entry objects */
|
||||||
struct work_struct initcb_work; /* Work for CB.InitCallBackState* */
|
struct work_struct initcb_work; /* Work for CB.InitCallBackState* */
|
||||||
struct afs_server *gc_next; /* Next server in manager's list */
|
struct afs_server *gc_next; /* Next server in manager's list */
|
||||||
time64_t unuse_time; /* Time at which last unused */
|
time64_t unuse_time; /* Time at which last unused */
|
||||||
@@ -549,12 +551,14 @@ struct afs_server {
|
|||||||
*/
|
*/
|
||||||
struct afs_server_entry {
|
struct afs_server_entry {
|
||||||
struct afs_server *server;
|
struct afs_server *server;
|
||||||
|
struct afs_volume *volume;
|
||||||
|
struct list_head slink; /* Link in server->volumes */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct afs_server_list {
|
struct afs_server_list {
|
||||||
struct rcu_head rcu;
|
struct rcu_head rcu;
|
||||||
afs_volid_t vids[AFS_MAXTYPES]; /* Volume IDs */
|
|
||||||
refcount_t usage;
|
refcount_t usage;
|
||||||
|
bool attached; /* T if attached to servers */
|
||||||
unsigned char nr_servers;
|
unsigned char nr_servers;
|
||||||
unsigned char preferred; /* Preferred server */
|
unsigned char preferred; /* Preferred server */
|
||||||
unsigned short vnovol_mask; /* Servers to be skipped due to VNOVOL */
|
unsigned short vnovol_mask; /* Servers to be skipped due to VNOVOL */
|
||||||
@@ -567,10 +571,9 @@ struct afs_server_list {
|
|||||||
* Live AFS volume management.
|
* Live AFS volume management.
|
||||||
*/
|
*/
|
||||||
struct afs_volume {
|
struct afs_volume {
|
||||||
union {
|
struct rcu_head rcu;
|
||||||
struct rcu_head rcu;
|
afs_volid_t vid; /* The volume ID of this volume */
|
||||||
afs_volid_t vid; /* volume ID */
|
afs_volid_t vids[AFS_MAXTYPES]; /* All associated volume IDs */
|
||||||
};
|
|
||||||
refcount_t ref;
|
refcount_t ref;
|
||||||
time64_t update_at; /* Time at which to next update */
|
time64_t update_at; /* Time at which to next update */
|
||||||
struct afs_cell *cell; /* Cell to which belongs (pins ref) */
|
struct afs_cell *cell; /* Cell to which belongs (pins ref) */
|
||||||
@@ -1450,10 +1453,14 @@ static inline struct afs_server_list *afs_get_serverlist(struct afs_server_list
|
|||||||
}
|
}
|
||||||
|
|
||||||
extern void afs_put_serverlist(struct afs_net *, struct afs_server_list *);
|
extern void afs_put_serverlist(struct afs_net *, struct afs_server_list *);
|
||||||
extern struct afs_server_list *afs_alloc_server_list(struct afs_cell *, struct key *,
|
struct afs_server_list *afs_alloc_server_list(struct afs_volume *volume,
|
||||||
struct afs_vldb_entry *,
|
struct key *key,
|
||||||
u8);
|
struct afs_vldb_entry *vldb);
|
||||||
extern bool afs_annotate_server_list(struct afs_server_list *, struct afs_server_list *);
|
extern bool afs_annotate_server_list(struct afs_server_list *, struct afs_server_list *);
|
||||||
|
void afs_attach_volume_to_servers(struct afs_volume *volume, struct afs_server_list *slist);
|
||||||
|
void afs_reattach_volume_to_servers(struct afs_volume *volume, struct afs_server_list *slist,
|
||||||
|
struct afs_server_list *old);
|
||||||
|
void afs_detach_volume_from_servers(struct afs_volume *volume, struct afs_server_list *slist);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* super.c
|
* super.c
|
||||||
|
|||||||
@@ -236,6 +236,7 @@ static struct afs_server *afs_alloc_server(struct afs_cell *cell,
|
|||||||
server->addr_version = alist->version;
|
server->addr_version = alist->version;
|
||||||
server->uuid = *uuid;
|
server->uuid = *uuid;
|
||||||
rwlock_init(&server->fs_lock);
|
rwlock_init(&server->fs_lock);
|
||||||
|
INIT_LIST_HEAD(&server->volumes);
|
||||||
INIT_WORK(&server->initcb_work, afs_server_init_callback_work);
|
INIT_WORK(&server->initcb_work, afs_server_init_callback_work);
|
||||||
init_waitqueue_head(&server->probe_wq);
|
init_waitqueue_head(&server->probe_wq);
|
||||||
INIT_LIST_HEAD(&server->probe_link);
|
INIT_LIST_HEAD(&server->probe_link);
|
||||||
|
|||||||
@@ -24,13 +24,13 @@ void afs_put_serverlist(struct afs_net *net, struct afs_server_list *slist)
|
|||||||
/*
|
/*
|
||||||
* Build a server list from a VLDB record.
|
* Build a server list from a VLDB record.
|
||||||
*/
|
*/
|
||||||
struct afs_server_list *afs_alloc_server_list(struct afs_cell *cell,
|
struct afs_server_list *afs_alloc_server_list(struct afs_volume *volume,
|
||||||
struct key *key,
|
struct key *key,
|
||||||
struct afs_vldb_entry *vldb,
|
struct afs_vldb_entry *vldb)
|
||||||
u8 type_mask)
|
|
||||||
{
|
{
|
||||||
struct afs_server_list *slist;
|
struct afs_server_list *slist;
|
||||||
struct afs_server *server;
|
struct afs_server *server;
|
||||||
|
unsigned int type_mask = 1 << volume->type;
|
||||||
int ret = -ENOMEM, nr_servers = 0, i, j;
|
int ret = -ENOMEM, nr_servers = 0, i, j;
|
||||||
|
|
||||||
for (i = 0; i < vldb->nr_servers; i++)
|
for (i = 0; i < vldb->nr_servers; i++)
|
||||||
@@ -44,15 +44,12 @@ struct afs_server_list *afs_alloc_server_list(struct afs_cell *cell,
|
|||||||
refcount_set(&slist->usage, 1);
|
refcount_set(&slist->usage, 1);
|
||||||
rwlock_init(&slist->lock);
|
rwlock_init(&slist->lock);
|
||||||
|
|
||||||
for (i = 0; i < AFS_MAXTYPES; i++)
|
|
||||||
slist->vids[i] = vldb->vid[i];
|
|
||||||
|
|
||||||
/* Make sure a records exists for each server in the list. */
|
/* Make sure a records exists for each server in the list. */
|
||||||
for (i = 0; i < vldb->nr_servers; i++) {
|
for (i = 0; i < vldb->nr_servers; i++) {
|
||||||
if (!(vldb->fs_mask[i] & type_mask))
|
if (!(vldb->fs_mask[i] & type_mask))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
server = afs_lookup_server(cell, key, &vldb->fs_server[i],
|
server = afs_lookup_server(volume->cell, key, &vldb->fs_server[i],
|
||||||
vldb->addr_version[i]);
|
vldb->addr_version[i]);
|
||||||
if (IS_ERR(server)) {
|
if (IS_ERR(server)) {
|
||||||
ret = PTR_ERR(server);
|
ret = PTR_ERR(server);
|
||||||
@@ -70,7 +67,7 @@ struct afs_server_list *afs_alloc_server_list(struct afs_cell *cell,
|
|||||||
break;
|
break;
|
||||||
if (j < slist->nr_servers) {
|
if (j < slist->nr_servers) {
|
||||||
if (slist->servers[j].server == server) {
|
if (slist->servers[j].server == server) {
|
||||||
afs_put_server(cell->net, server,
|
afs_put_server(volume->cell->net, server,
|
||||||
afs_server_trace_put_slist_isort);
|
afs_server_trace_put_slist_isort);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -81,6 +78,7 @@ struct afs_server_list *afs_alloc_server_list(struct afs_cell *cell,
|
|||||||
}
|
}
|
||||||
|
|
||||||
slist->servers[j].server = server;
|
slist->servers[j].server = server;
|
||||||
|
slist->servers[j].volume = volume;
|
||||||
slist->nr_servers++;
|
slist->nr_servers++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,7 +90,7 @@ struct afs_server_list *afs_alloc_server_list(struct afs_cell *cell,
|
|||||||
return slist;
|
return slist;
|
||||||
|
|
||||||
error_2:
|
error_2:
|
||||||
afs_put_serverlist(cell->net, slist);
|
afs_put_serverlist(volume->cell->net, slist);
|
||||||
error:
|
error:
|
||||||
return ERR_PTR(ret);
|
return ERR_PTR(ret);
|
||||||
}
|
}
|
||||||
@@ -127,3 +125,99 @@ changed:
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Attach a volume to the servers it is going to use.
|
||||||
|
*/
|
||||||
|
void afs_attach_volume_to_servers(struct afs_volume *volume, struct afs_server_list *slist)
|
||||||
|
{
|
||||||
|
struct afs_server_entry *se, *pe;
|
||||||
|
struct afs_server *server;
|
||||||
|
struct list_head *p;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
spin_lock(&volume->cell->vs_lock);
|
||||||
|
|
||||||
|
for (i = 0; i < slist->nr_servers; i++) {
|
||||||
|
se = &slist->servers[i];
|
||||||
|
server = se->server;
|
||||||
|
|
||||||
|
list_for_each(p, &server->volumes) {
|
||||||
|
pe = list_entry(p, struct afs_server_entry, slink);
|
||||||
|
if (volume->vid <= pe->volume->vid)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
list_add_tail_rcu(&se->slink, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
slist->attached = true;
|
||||||
|
spin_unlock(&volume->cell->vs_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reattach a volume to the servers it is going to use when server list is
|
||||||
|
* replaced. We try to switch the attachment points to avoid rewalking the
|
||||||
|
* lists.
|
||||||
|
*/
|
||||||
|
void afs_reattach_volume_to_servers(struct afs_volume *volume, struct afs_server_list *new,
|
||||||
|
struct afs_server_list *old)
|
||||||
|
{
|
||||||
|
unsigned int n = 0, o = 0;
|
||||||
|
|
||||||
|
spin_lock(&volume->cell->vs_lock);
|
||||||
|
|
||||||
|
while (n < new->nr_servers || o < old->nr_servers) {
|
||||||
|
struct afs_server_entry *pn = n < new->nr_servers ? &new->servers[n] : NULL;
|
||||||
|
struct afs_server_entry *po = o < old->nr_servers ? &old->servers[o] : NULL;
|
||||||
|
struct afs_server_entry *s;
|
||||||
|
struct list_head *p;
|
||||||
|
int diff;
|
||||||
|
|
||||||
|
if (pn && po && pn->server == po->server) {
|
||||||
|
list_replace_rcu(&po->slink, &pn->slink);
|
||||||
|
n++;
|
||||||
|
o++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pn && po)
|
||||||
|
diff = memcmp(&pn->server->uuid, &po->server->uuid,
|
||||||
|
sizeof(pn->server->uuid));
|
||||||
|
else
|
||||||
|
diff = pn ? -1 : 1;
|
||||||
|
|
||||||
|
if (diff < 0) {
|
||||||
|
list_for_each(p, &pn->server->volumes) {
|
||||||
|
s = list_entry(p, struct afs_server_entry, slink);
|
||||||
|
if (volume->vid <= s->volume->vid)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
list_add_tail_rcu(&pn->slink, p);
|
||||||
|
n++;
|
||||||
|
} else {
|
||||||
|
list_del_rcu(&po->slink);
|
||||||
|
o++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
spin_unlock(&volume->cell->vs_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Detach a volume from the servers it has been using.
|
||||||
|
*/
|
||||||
|
void afs_detach_volume_from_servers(struct afs_volume *volume, struct afs_server_list *slist)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
if (!slist->attached)
|
||||||
|
return;
|
||||||
|
|
||||||
|
spin_lock(&volume->cell->vs_lock);
|
||||||
|
|
||||||
|
for (i = 0; i < slist->nr_servers; i++)
|
||||||
|
list_del_rcu(&slist->servers[i].slink);
|
||||||
|
|
||||||
|
slist->attached = false;
|
||||||
|
spin_unlock(&volume->cell->vs_lock);
|
||||||
|
}
|
||||||
|
|||||||
@@ -126,7 +126,7 @@ static int afs_compare_volume_slists(const struct afs_volume *vol_a,
|
|||||||
lb = rcu_dereference(vol_b->servers);
|
lb = rcu_dereference(vol_b->servers);
|
||||||
|
|
||||||
for (i = 0; i < AFS_MAXTYPES; i++)
|
for (i = 0; i < AFS_MAXTYPES; i++)
|
||||||
if (la->vids[i] != lb->vids[i])
|
if (vol_a->vids[i] != vol_b->vids[i])
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
while (a < la->nr_servers && b < lb->nr_servers) {
|
while (a < la->nr_servers && b < lb->nr_servers) {
|
||||||
|
|||||||
@@ -72,11 +72,11 @@ static void afs_remove_volume_from_cell(struct afs_volume *volume)
|
|||||||
*/
|
*/
|
||||||
static struct afs_volume *afs_alloc_volume(struct afs_fs_context *params,
|
static struct afs_volume *afs_alloc_volume(struct afs_fs_context *params,
|
||||||
struct afs_vldb_entry *vldb,
|
struct afs_vldb_entry *vldb,
|
||||||
unsigned long type_mask)
|
struct afs_server_list **_slist)
|
||||||
{
|
{
|
||||||
struct afs_server_list *slist;
|
struct afs_server_list *slist;
|
||||||
struct afs_volume *volume;
|
struct afs_volume *volume;
|
||||||
int ret = -ENOMEM;
|
int ret = -ENOMEM, i;
|
||||||
|
|
||||||
volume = kzalloc(sizeof(struct afs_volume), GFP_KERNEL);
|
volume = kzalloc(sizeof(struct afs_volume), GFP_KERNEL);
|
||||||
if (!volume)
|
if (!volume)
|
||||||
@@ -95,13 +95,16 @@ static struct afs_volume *afs_alloc_volume(struct afs_fs_context *params,
|
|||||||
rwlock_init(&volume->cb_v_break_lock);
|
rwlock_init(&volume->cb_v_break_lock);
|
||||||
memcpy(volume->name, vldb->name, vldb->name_len + 1);
|
memcpy(volume->name, vldb->name, vldb->name_len + 1);
|
||||||
|
|
||||||
slist = afs_alloc_server_list(params->cell, params->key, vldb, type_mask);
|
for (i = 0; i < AFS_MAXTYPES; i++)
|
||||||
|
volume->vids[i] = vldb->vid[i];
|
||||||
|
|
||||||
|
slist = afs_alloc_server_list(volume, params->key, vldb);
|
||||||
if (IS_ERR(slist)) {
|
if (IS_ERR(slist)) {
|
||||||
ret = PTR_ERR(slist);
|
ret = PTR_ERR(slist);
|
||||||
goto error_1;
|
goto error_1;
|
||||||
}
|
}
|
||||||
|
|
||||||
refcount_set(&slist->usage, 1);
|
*_slist = slist;
|
||||||
rcu_assign_pointer(volume->servers, slist);
|
rcu_assign_pointer(volume->servers, slist);
|
||||||
trace_afs_volume(volume->vid, 1, afs_volume_trace_alloc);
|
trace_afs_volume(volume->vid, 1, afs_volume_trace_alloc);
|
||||||
return volume;
|
return volume;
|
||||||
@@ -117,17 +120,19 @@ error_0:
|
|||||||
* Look up or allocate a volume record.
|
* Look up or allocate a volume record.
|
||||||
*/
|
*/
|
||||||
static struct afs_volume *afs_lookup_volume(struct afs_fs_context *params,
|
static struct afs_volume *afs_lookup_volume(struct afs_fs_context *params,
|
||||||
struct afs_vldb_entry *vldb,
|
struct afs_vldb_entry *vldb)
|
||||||
unsigned long type_mask)
|
|
||||||
{
|
{
|
||||||
|
struct afs_server_list *slist;
|
||||||
struct afs_volume *candidate, *volume;
|
struct afs_volume *candidate, *volume;
|
||||||
|
|
||||||
candidate = afs_alloc_volume(params, vldb, type_mask);
|
candidate = afs_alloc_volume(params, vldb, &slist);
|
||||||
if (IS_ERR(candidate))
|
if (IS_ERR(candidate))
|
||||||
return candidate;
|
return candidate;
|
||||||
|
|
||||||
volume = afs_insert_volume_into_cell(params->cell, candidate);
|
volume = afs_insert_volume_into_cell(params->cell, candidate);
|
||||||
if (volume != candidate)
|
if (volume == candidate)
|
||||||
|
afs_attach_volume_to_servers(volume, slist);
|
||||||
|
else
|
||||||
afs_put_volume(params->net, candidate, afs_volume_trace_put_cell_dup);
|
afs_put_volume(params->net, candidate, afs_volume_trace_put_cell_dup);
|
||||||
return volume;
|
return volume;
|
||||||
}
|
}
|
||||||
@@ -208,8 +213,7 @@ struct afs_volume *afs_create_volume(struct afs_fs_context *params)
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
type_mask = 1UL << params->type;
|
volume = afs_lookup_volume(params, vldb);
|
||||||
volume = afs_lookup_volume(params, vldb, type_mask);
|
|
||||||
|
|
||||||
error:
|
error:
|
||||||
kfree(vldb);
|
kfree(vldb);
|
||||||
@@ -221,14 +225,17 @@ error:
|
|||||||
*/
|
*/
|
||||||
static void afs_destroy_volume(struct afs_net *net, struct afs_volume *volume)
|
static void afs_destroy_volume(struct afs_net *net, struct afs_volume *volume)
|
||||||
{
|
{
|
||||||
|
struct afs_server_list *slist = rcu_access_pointer(volume->servers);
|
||||||
|
|
||||||
_enter("%p", volume);
|
_enter("%p", volume);
|
||||||
|
|
||||||
#ifdef CONFIG_AFS_FSCACHE
|
#ifdef CONFIG_AFS_FSCACHE
|
||||||
ASSERTCMP(volume->cache, ==, NULL);
|
ASSERTCMP(volume->cache, ==, NULL);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
afs_detach_volume_from_servers(volume, slist);
|
||||||
afs_remove_volume_from_cell(volume);
|
afs_remove_volume_from_cell(volume);
|
||||||
afs_put_serverlist(net, rcu_access_pointer(volume->servers));
|
afs_put_serverlist(net, slist);
|
||||||
afs_put_cell(volume->cell, afs_cell_trace_put_vol);
|
afs_put_cell(volume->cell, afs_cell_trace_put_vol);
|
||||||
trace_afs_volume(volume->vid, refcount_read(&volume->ref),
|
trace_afs_volume(volume->vid, refcount_read(&volume->ref),
|
||||||
afs_volume_trace_free);
|
afs_volume_trace_free);
|
||||||
@@ -362,8 +369,7 @@ static int afs_update_volume_status(struct afs_volume *volume, struct key *key)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* See if the volume's server list got updated. */
|
/* See if the volume's server list got updated. */
|
||||||
new = afs_alloc_server_list(volume->cell, key,
|
new = afs_alloc_server_list(volume, key, vldb);
|
||||||
vldb, (1 << volume->type));
|
|
||||||
if (IS_ERR(new)) {
|
if (IS_ERR(new)) {
|
||||||
ret = PTR_ERR(new);
|
ret = PTR_ERR(new);
|
||||||
goto error_vldb;
|
goto error_vldb;
|
||||||
@@ -384,9 +390,11 @@ static int afs_update_volume_status(struct afs_volume *volume, struct key *key)
|
|||||||
|
|
||||||
volume->update_at = ktime_get_real_seconds() + afs_volume_record_life;
|
volume->update_at = ktime_get_real_seconds() + afs_volume_record_life;
|
||||||
write_unlock(&volume->servers_lock);
|
write_unlock(&volume->servers_lock);
|
||||||
ret = 0;
|
|
||||||
|
|
||||||
|
if (discard == old)
|
||||||
|
afs_reattach_volume_to_servers(volume, new, old);
|
||||||
afs_put_serverlist(volume->cell->net, discard);
|
afs_put_serverlist(volume->cell->net, discard);
|
||||||
|
ret = 0;
|
||||||
error_vldb:
|
error_vldb:
|
||||||
kfree(vldb);
|
kfree(vldb);
|
||||||
error:
|
error:
|
||||||
|
|||||||
Reference in New Issue
Block a user