Skip to content

Commit

Permalink
afs: Lay the groundwork for supporting network namespaces
Browse files Browse the repository at this point in the history
Lay the groundwork for supporting network namespaces (netns) to the AFS
filesystem by moving various global features to a network-namespace struct
(afs_net) and providing an instance of this as a temporary global variable
that everything uses via accessor functions for the moment.

The following changes have been made:

 (1) Store the netns in the superblock info.  This will be obtained from
     the mounter's nsproxy on a manual mount and inherited from the parent
     superblock on an automount.

 (2) The cell list is made per-netns.  It can be viewed through
     /proc/net/afs/cells and also be modified by writing commands to that
     file.

 (3) The local workstation cell is set per-ns in /proc/net/afs/rootcell.
     This is unset by default.

 (4) The 'rootcell' module parameter, which sets a cell and VL server list
     modifies the init net namespace, thereby allowing an AFS root fs to be
     theoretically used.

 (5) The volume location lists and the file lock manager are made
     per-netns.

 (6) The AF_RXRPC socket and associated I/O bits are made per-ns.

The various workqueues remain global for the moment.

Changes still to be made:

 (1) /proc/fs/afs/ should be moved to /proc/net/afs/ and a symlink emplaced
     from the old name.

 (2) A per-netns subsys needs to be registered for AFS into which it can
     store its per-netns data.

 (3) Rather than the AF_RXRPC socket being opened on module init, it needs
     to be opened on the creation of a superblock in that netns.

 (4) The socket needs to be closed when the last superblock using it is
     destroyed and all outstanding client calls on it have been completed.
     This prevents a reference loop on the namespace.

 (5) It is possible that several namespaces will want to use AFS, in which
     case each one will need its own UDP port.  These can either be set
     through /proc/net/afs/cm_port or the kernel can pick one at random.
     The init_ns gets 7001 by default.

Other issues that need resolving:

 (1) The DNS keyring needs net-namespacing.

 (2) Where do upcalls go (eg. DNS request-key upcall)?

 (3) Need something like open_socket_in_file_ns() syscall so that AFS
     command line tools attempting to operate on an AFS file/volume have
     their RPC calls go to the right place.

Signed-off-by: David Howells <dhowells@redhat.com>
  • Loading branch information
David Howells committed Nov 13, 2017
1 parent 5e4def2 commit f044c88
Show file tree
Hide file tree
Showing 16 changed files with 603 additions and 492 deletions.
9 changes: 9 additions & 0 deletions fs/afs/afs.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,15 @@ struct afs_callback {

#define AFSCBMAX 50 /* maximum callbacks transferred per bulk op */

struct afs_uuid {
__be32 time_low; /* low part of timestamp */
__be16 time_mid; /* mid part of timestamp */
__be16 time_hi_and_version; /* high part of timestamp and version */
__u8 clock_seq_hi_and_reserved; /* clock seq hi and variant */
__u8 clock_seq_low; /* clock seq low */
__u8 node[6]; /* spatially unique node ID (MAC addr) */
};

/*
* AFS volume information
*/
Expand Down
24 changes: 2 additions & 22 deletions fs/afs/callback.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,7 @@ unsigned afs_vnode_update_timeout = 10;
CIRC_SPACE((server)->cb_break_head, (server)->cb_break_tail, \
ARRAY_SIZE((server)->cb_break))

//static void afs_callback_updater(struct work_struct *);

static struct workqueue_struct *afs_callback_update_worker;
struct workqueue_struct *afs_callback_update_worker;

/*
* allow the fileserver to request callback state (re-)initialisation
Expand Down Expand Up @@ -343,7 +341,7 @@ void afs_dispatch_give_up_callbacks(struct work_struct *work)
* had callbacks entirely, and the server will call us later to break
* them
*/
afs_fs_give_up_callbacks(server, true);
afs_fs_give_up_callbacks(server->cell->net, server, true);
}

/*
Expand Down Expand Up @@ -456,21 +454,3 @@ static void afs_callback_updater(struct work_struct *work)
afs_put_vnode(vl);
}
#endif

/*
* initialise the callback update process
*/
int __init afs_callback_update_init(void)
{
afs_callback_update_worker = alloc_ordered_workqueue("kafs_callbackd",
WQ_MEM_RECLAIM);
return afs_callback_update_worker ? 0 : -ENOMEM;
}

/*
* shut down the callback update process
*/
void afs_callback_update_kill(void)
{
destroy_workqueue(afs_callback_update_worker);
}
130 changes: 63 additions & 67 deletions fs/afs/cell.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,12 @@
#include <keys/rxrpc-type.h>
#include "internal.h"

DECLARE_RWSEM(afs_proc_cells_sem);
LIST_HEAD(afs_proc_cells);

static LIST_HEAD(afs_cells);
static DEFINE_RWLOCK(afs_cells_lock);
static DECLARE_RWSEM(afs_cells_sem); /* add/remove serialisation */
static DECLARE_WAIT_QUEUE_HEAD(afs_cells_freeable_wq);
static struct afs_cell *afs_cell_root;

/*
* allocate a cell record and fill in its name, VL server address list and
* allocate an anonymous key
*/
static struct afs_cell *afs_cell_alloc(const char *name, unsigned namelen,
static struct afs_cell *afs_cell_alloc(struct afs_net *net,
const char *name, unsigned namelen,
char *vllist)
{
struct afs_cell *cell;
Expand Down Expand Up @@ -62,6 +54,7 @@ static struct afs_cell *afs_cell_alloc(const char *name, unsigned namelen,

atomic_set(&cell->usage, 1);
INIT_LIST_HEAD(&cell->link);
cell->net = net;
rwlock_init(&cell->servers_lock);
INIT_LIST_HEAD(&cell->servers);
init_rwsem(&cell->vl_sem);
Expand Down Expand Up @@ -142,36 +135,38 @@ static struct afs_cell *afs_cell_alloc(const char *name, unsigned namelen,

/*
* afs_cell_crate() - create a cell record
* @net: The network namespace
* @name: is the name of the cell.
* @namsesz: is the strlen of the cell name.
* @vllist: is a colon separated list of IP addresses in "a.b.c.d" format.
* @retref: is T to return the cell reference when the cell exists.
*/
struct afs_cell *afs_cell_create(const char *name, unsigned namesz,
struct afs_cell *afs_cell_create(struct afs_net *net,
const char *name, unsigned namesz,
char *vllist, bool retref)
{
struct afs_cell *cell;
int ret;

_enter("%*.*s,%s", namesz, namesz, name ?: "", vllist);

down_write(&afs_cells_sem);
read_lock(&afs_cells_lock);
list_for_each_entry(cell, &afs_cells, link) {
down_write(&net->cells_sem);
read_lock(&net->cells_lock);
list_for_each_entry(cell, &net->cells, link) {
if (strncasecmp(cell->name, name, namesz) == 0)
goto duplicate_name;
}
read_unlock(&afs_cells_lock);
read_unlock(&net->cells_lock);

cell = afs_cell_alloc(name, namesz, vllist);
cell = afs_cell_alloc(net, name, namesz, vllist);
if (IS_ERR(cell)) {
_leave(" = %ld", PTR_ERR(cell));
up_write(&afs_cells_sem);
up_write(&net->cells_sem);
return cell;
}

/* add a proc directory for this cell */
ret = afs_proc_cell_setup(cell);
ret = afs_proc_cell_setup(net, cell);
if (ret < 0)
goto error;

Expand All @@ -183,20 +178,20 @@ struct afs_cell *afs_cell_create(const char *name, unsigned namesz,
#endif

/* add to the cell lists */
write_lock(&afs_cells_lock);
list_add_tail(&cell->link, &afs_cells);
write_unlock(&afs_cells_lock);
write_lock(&net->cells_lock);
list_add_tail(&cell->link, &net->cells);
write_unlock(&net->cells_lock);

down_write(&afs_proc_cells_sem);
list_add_tail(&cell->proc_link, &afs_proc_cells);
up_write(&afs_proc_cells_sem);
up_write(&afs_cells_sem);
down_write(&net->proc_cells_sem);
list_add_tail(&cell->proc_link, &net->proc_cells);
up_write(&net->proc_cells_sem);
up_write(&net->cells_sem);

_leave(" = %p", cell);
return cell;

error:
up_write(&afs_cells_sem);
up_write(&net->cells_sem);
key_put(cell->anonymous_key);
kfree(cell);
_leave(" = %d", ret);
Expand All @@ -206,8 +201,8 @@ struct afs_cell *afs_cell_create(const char *name, unsigned namesz,
if (retref && !IS_ERR(cell))
afs_get_cell(cell);

read_unlock(&afs_cells_lock);
up_write(&afs_cells_sem);
read_unlock(&net->cells_lock);
up_write(&net->cells_sem);

if (retref) {
_leave(" = %p", cell);
Expand All @@ -223,7 +218,7 @@ struct afs_cell *afs_cell_create(const char *name, unsigned namesz,
* - can be called with a module parameter string
* - can be called from a write to /proc/fs/afs/rootcell
*/
int afs_cell_init(char *rootcell)
int afs_cell_init(struct afs_net *net, char *rootcell)
{
struct afs_cell *old_root, *new_root;
char *cp;
Expand All @@ -245,17 +240,17 @@ int afs_cell_init(char *rootcell)
*cp++ = 0;

/* allocate a cell record for the root cell */
new_root = afs_cell_create(rootcell, strlen(rootcell), cp, false);
new_root = afs_cell_create(net, rootcell, strlen(rootcell), cp, false);
if (IS_ERR(new_root)) {
_leave(" = %ld", PTR_ERR(new_root));
return PTR_ERR(new_root);
}

/* install the new cell */
write_lock(&afs_cells_lock);
old_root = afs_cell_root;
afs_cell_root = new_root;
write_unlock(&afs_cells_lock);
write_lock(&net->cells_lock);
old_root = net->ws_cell;
net->ws_cell = new_root;
write_unlock(&net->cells_lock);
afs_put_cell(old_root);

_leave(" = 0");
Expand All @@ -265,19 +260,20 @@ int afs_cell_init(char *rootcell)
/*
* lookup a cell record
*/
struct afs_cell *afs_cell_lookup(const char *name, unsigned namesz,
struct afs_cell *afs_cell_lookup(struct afs_net *net,
const char *name, unsigned namesz,
bool dns_cell)
{
struct afs_cell *cell;

_enter("\"%*.*s\",", namesz, namesz, name ?: "");

down_read(&afs_cells_sem);
read_lock(&afs_cells_lock);
down_read(&net->cells_sem);
read_lock(&net->cells_lock);

if (name) {
/* if the cell was named, look for it in the cell record list */
list_for_each_entry(cell, &afs_cells, link) {
list_for_each_entry(cell, &net->cells, link) {
if (strncmp(cell->name, name, namesz) == 0) {
afs_get_cell(cell);
goto found;
Expand All @@ -289,7 +285,7 @@ struct afs_cell *afs_cell_lookup(const char *name, unsigned namesz,
found:
;
} else {
cell = afs_cell_root;
cell = net->ws_cell;
if (!cell) {
/* this should not happen unless user tries to mount
* when root cell is not set. Return an impossibly
Expand All @@ -304,16 +300,16 @@ struct afs_cell *afs_cell_lookup(const char *name, unsigned namesz,

}

read_unlock(&afs_cells_lock);
up_read(&afs_cells_sem);
read_unlock(&net->cells_lock);
up_read(&net->cells_sem);
_leave(" = %p", cell);
return cell;

create_cell:
read_unlock(&afs_cells_lock);
up_read(&afs_cells_sem);
read_unlock(&net->cells_lock);
up_read(&net->cells_sem);

cell = afs_cell_create(name, namesz, NULL, true);
cell = afs_cell_create(net, name, namesz, NULL, true);

_leave(" = %p", cell);
return cell;
Expand All @@ -325,14 +321,14 @@ struct afs_cell *afs_cell_lookup(const char *name, unsigned namesz,
*/
struct afs_cell *afs_get_cell_maybe(struct afs_cell *cell)
{
write_lock(&afs_cells_lock);
write_lock(&net->cells_lock);

if (cell && !list_empty(&cell->link))
afs_get_cell(cell);
else
cell = NULL;

write_unlock(&afs_cells_lock);
write_unlock(&net->cells_lock);
return cell;
}
#endif /* 0 */
Expand All @@ -351,30 +347,30 @@ void afs_put_cell(struct afs_cell *cell)

/* to prevent a race, the decrement and the dequeue must be effectively
* atomic */
write_lock(&afs_cells_lock);
write_lock(&cell->net->cells_lock);

if (likely(!atomic_dec_and_test(&cell->usage))) {
write_unlock(&afs_cells_lock);
write_unlock(&cell->net->cells_lock);
_leave("");
return;
}

ASSERT(list_empty(&cell->servers));
ASSERT(list_empty(&cell->vl_list));

write_unlock(&afs_cells_lock);
wake_up(&cell->net->cells_freeable_wq);

wake_up(&afs_cells_freeable_wq);
write_unlock(&cell->net->cells_lock);

_leave(" [unused]");
}

/*
* destroy a cell record
* - must be called with the afs_cells_sem write-locked
* - must be called with the net->cells_sem write-locked
* - cell->link should have been broken by the caller
*/
static void afs_cell_destroy(struct afs_cell *cell)
static void afs_cell_destroy(struct afs_net *net, struct afs_cell *cell)
{
_enter("%p{%d,%s}", cell, atomic_read(&cell->usage), cell->name);

Expand All @@ -387,14 +383,14 @@ static void afs_cell_destroy(struct afs_cell *cell)

_debug("wait for cell %s", cell->name);
set_current_state(TASK_UNINTERRUPTIBLE);
add_wait_queue(&afs_cells_freeable_wq, &myself);
add_wait_queue(&net->cells_freeable_wq, &myself);

while (atomic_read(&cell->usage) > 0) {
schedule();
set_current_state(TASK_UNINTERRUPTIBLE);
}

remove_wait_queue(&afs_cells_freeable_wq, &myself);
remove_wait_queue(&net->cells_freeable_wq, &myself);
set_current_state(TASK_RUNNING);
}

Expand All @@ -403,11 +399,11 @@ static void afs_cell_destroy(struct afs_cell *cell)
ASSERT(list_empty(&cell->servers));
ASSERT(list_empty(&cell->vl_list));

afs_proc_cell_remove(cell);
afs_proc_cell_remove(net, cell);

down_write(&afs_proc_cells_sem);
down_write(&net->proc_cells_sem);
list_del_init(&cell->proc_link);
up_write(&afs_proc_cells_sem);
up_write(&net->proc_cells_sem);

#ifdef CONFIG_AFS_FSCACHE
fscache_relinquish_cookie(cell->cache, 0);
Expand All @@ -422,39 +418,39 @@ static void afs_cell_destroy(struct afs_cell *cell)
* purge in-memory cell database on module unload or afs_init() failure
* - the timeout daemon is stopped before calling this
*/
void afs_cell_purge(void)
void afs_cell_purge(struct afs_net *net)
{
struct afs_cell *cell;

_enter("");

afs_put_cell(afs_cell_root);
afs_put_cell(net->ws_cell);

down_write(&afs_cells_sem);
down_write(&net->cells_sem);

while (!list_empty(&afs_cells)) {
while (!list_empty(&net->cells)) {
cell = NULL;

/* remove the next cell from the front of the list */
write_lock(&afs_cells_lock);
write_lock(&net->cells_lock);

if (!list_empty(&afs_cells)) {
cell = list_entry(afs_cells.next,
if (!list_empty(&net->cells)) {
cell = list_entry(net->cells.next,
struct afs_cell, link);
list_del_init(&cell->link);
}

write_unlock(&afs_cells_lock);
write_unlock(&net->cells_lock);

if (cell) {
_debug("PURGING CELL %s (%d)",
cell->name, atomic_read(&cell->usage));

/* now the cell should be left with no references */
afs_cell_destroy(cell);
afs_cell_destroy(net, cell);
}
}

up_write(&afs_cells_sem);
up_write(&net->cells_sem);
_leave("");
}
Loading

0 comments on commit f044c88

Please sign in to comment.