Commit f044c884 authored by David Howells's avatar David Howells

afs: Lay the groundwork for supporting network namespaces

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: default avatarDavid Howells <dhowells@redhat.com>
parent 5e4def20
......@@ -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
*/
......
......@@ -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
......@@ -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);
}
/*
......@@ -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);
}
......@@ -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;
......@@ -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);
......@@ -142,12 +135,14 @@ 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;
......@@ -155,23 +150,23 @@ struct afs_cell *afs_cell_create(const char *name, unsigned namesz,
_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;
......@@ -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);
......@@ -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);
......@@ -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;
......@@ -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");
......@@ -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;
......@@ -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
......@@ -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;
......@@ -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 */
......@@ -351,10 +347,10 @@ 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;
}
......@@ -362,19 +358,19 @@ void afs_put_cell(struct afs_cell *cell)
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);
......@@ -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);
}
......@@ -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);
......@@ -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("");
}
......@@ -193,7 +193,7 @@ static int afs_deliver_cb_callback(struct afs_call *call)
switch (call->unmarshall) {
case 0:
rxrpc_kernel_get_peer(afs_socket, call->rxcall, &srx);
rxrpc_kernel_get_peer(call->net->socket, call->rxcall, &srx);
call->offset = 0;
call->unmarshall++;
......@@ -290,7 +290,7 @@ static int afs_deliver_cb_callback(struct afs_call *call)
/* we'll need the file server record as that tells us which set of
* vnodes to operate upon */
server = afs_find_server(&srx);
server = afs_find_server(call->net, &srx);
if (!server)
return -ENOTCONN;
call->server = server;
......@@ -324,7 +324,7 @@ static int afs_deliver_cb_init_call_back_state(struct afs_call *call)
_enter("");
rxrpc_kernel_get_peer(afs_socket, call->rxcall, &srx);
rxrpc_kernel_get_peer(call->net->socket, call->rxcall, &srx);
ret = afs_extract_data(call, NULL, 0, false);
if (ret < 0)
......@@ -335,7 +335,7 @@ static int afs_deliver_cb_init_call_back_state(struct afs_call *call)
/* we'll need the file server record as that tells us which set of
* vnodes to operate upon */
server = afs_find_server(&srx);
server = afs_find_server(call->net, &srx);
if (!server)
return -ENOTCONN;
call->server = server;
......@@ -357,7 +357,7 @@ static int afs_deliver_cb_init_call_back_state3(struct afs_call *call)
_enter("");
rxrpc_kernel_get_peer(afs_socket, call->rxcall, &srx);
rxrpc_kernel_get_peer(call->net->socket, call->rxcall, &srx);
_enter("{%u}", call->unmarshall);
......@@ -407,7 +407,7 @@ static int afs_deliver_cb_init_call_back_state3(struct afs_call *call)
/* we'll need the file server record as that tells us which set of
* vnodes to operate upon */
server = afs_find_server(&srx);
server = afs_find_server(call->net, &srx);
if (!server)
return -ENOTCONN;
call->server = server;
......@@ -461,7 +461,7 @@ static void SRXAFSCB_ProbeUuid(struct work_struct *work)
_enter("");
if (memcmp(r, &afs_uuid, sizeof(afs_uuid)) == 0)
if (memcmp(r, &call->net->uuid, sizeof(call->net->uuid)) == 0)
reply.match = htonl(0);
else
reply.match = htonl(1);
......@@ -568,13 +568,13 @@ static void SRXAFSCB_TellMeAboutYourself(struct work_struct *work)
memset(&reply, 0, sizeof(reply));
reply.ia.nifs = htonl(nifs);
reply.ia.uuid[0] = afs_uuid.time_low;
reply.ia.uuid[1] = htonl(ntohs(afs_uuid.time_mid));
reply.ia.uuid[2] = htonl(ntohs(afs_uuid.time_hi_and_version));
reply.ia.uuid[3] = htonl((s8) afs_uuid.clock_seq_hi_and_reserved);
reply.ia.uuid[4] = htonl((s8) afs_uuid.clock_seq_low);
reply.ia.uuid[0] = call->net->uuid.time_low;
reply.ia.uuid[1] = htonl(ntohs(call->net->uuid.time_mid));
reply.ia.uuid[2] = htonl(ntohs(call->net->uuid.time_hi_and_version));
reply.ia.uuid[3] = htonl((s8) call->net->uuid.clock_seq_hi_and_reserved);
reply.ia.uuid[4] = htonl((s8) call->net->uuid.clock_seq_low);
for (loop = 0; loop < 6; loop++)
reply.ia.uuid[loop + 5] = htonl((s8) afs_uuid.node[loop]);
reply.ia.uuid[loop + 5] = htonl((s8) call->net->uuid.node[loop]);
if (ifs) {
for (loop = 0; loop < nifs; loop++) {
......
......@@ -14,47 +14,16 @@
#define AFS_LOCK_GRANTED 0
#define AFS_LOCK_PENDING 1
struct workqueue_struct *afs_lock_manager;
static void afs_fl_copy_lock(struct file_lock *new, struct file_lock *fl);
static void afs_fl_release_private(struct file_lock *fl);
static struct workqueue_struct *afs_lock_manager;
static DEFINE_MUTEX(afs_lock_manager_mutex);
static const struct file_lock_operations afs_lock_ops = {
.fl_copy_lock = afs_fl_copy_lock,
.fl_release_private = afs_fl_release_private,
};
/*
* initialise the lock manager thread if it isn't already running
*/
static int afs_init_lock_manager(void)
{
int ret;
ret = 0;
if (!afs_lock_manager) {
mutex_lock(&afs_lock_manager_mutex);
if (!afs_lock_manager) {
afs_lock_manager = alloc_workqueue("kafs_lockd",
WQ_MEM_RECLAIM, 0);
if (!afs_lock_manager)
ret = -ENOMEM;
}
mutex_unlock(&afs_lock_manager_mutex);
}
return ret;
}
/*
* destroy the lock manager thread if it's running
*/
void __exit afs_kill_lock_manager(void)
{
if (afs_lock_manager)
destroy_workqueue(afs_lock_manager);
}
/*
* if the callback is broken on this vnode, then the lock may now be available
*/
......@@ -264,10 +233,6 @@ static int afs_do_setlk(struct file *file, struct file_lock *fl)
if (fl->fl_start != 0 || fl->fl_end != OFFSET_MAX)
return -EINVAL;
ret = afs_init_lock_manager();
if (ret < 0)
return ret;
fl->fl_ops = &afs_lock_ops;
INIT_LIST_HEAD(&fl->fl_u.afs.link);
fl->fl_u.afs.state = AFS_LOCK_PENDING;
......
......@@ -284,12 +284,13 @@ int afs_fs_fetch_file_status(struct afs_server *server,
bool async)
{
struct afs_call *call;
struct afs_net *net = afs_v2net(vnode);
__be32 *bp;
_enter(",%x,{%x:%u},,",
key_serial(key), vnode->fid.vid, vnode->fid.vnode);
call = afs_alloc_flat_call(&afs_RXFSFetchStatus, 16, (21 + 3 + 6) * 4);
call = afs_alloc_flat_call(net, &afs_RXFSFetchStatus, 16, (21 + 3 + 6) * 4);
if (!call)
return -ENOMEM;
......@@ -490,11 +491,12 @@ static int afs_fs_fetch_data64(struct afs_server *server,
bool async)
{
struct afs_call *call;
struct afs_net *net = afs_v2net(vnode);
__be32 *bp;
_enter("");
call = afs_alloc_flat_call(&afs_RXFSFetchData64, 32, (21 + 3 + 6) * 4);
call = afs_alloc_flat_call(net, &afs_RXFSFetchData64, 32, (21 + 3 + 6) * 4);
if (!call)
return -ENOMEM;
......@@ -531,6 +533,7 @@ int afs_fs_fetch_data(struct afs_server *server,
bool async)
{
struct afs_call *call;
struct afs_net *net = afs_v2net(vnode);
__be32 *bp;
if (upper_32_bits(req->pos) ||
......@@ -540,7 +543,7 @@ int afs_fs_fetch_data(struct afs_server *server,
_enter("");
call = afs_alloc_flat_call(&afs_RXFSFetchData, 24, (21 + 3 + 6) * 4);
call = afs_alloc_flat_call(net, &afs_RXFSFetchData, 24, (21 + 3 + 6) * 4);
if (!call)
return -ENOMEM;
......@@ -590,7 +593,8 @@ static const struct afs_call_type afs_RXFSGiveUpCallBacks = {
* give up a set of callbacks
* - the callbacks are held in the server->cb_break ring
*/
int afs_fs_give_up_callbacks(struct afs_server *server,
int afs_fs_give_up_callbacks(struct afs_net *net,
struct afs_server *server,
bool async)
{
struct afs_call *call;
......@@ -610,7 +614,7 @@ int afs_fs_give_up_callbacks(struct afs_server *server,
_debug("break %zu callbacks", ncallbacks);
call = afs_alloc_flat_call(&afs_RXFSGiveUpCallBacks,
call = afs_alloc_flat_call(net, &afs_RXFSGiveUpCallBacks,
12 + ncallbacks * 6 * 4, 0);
if (!call)
return -ENOMEM;
......@@ -699,6 +703,7 @@ int afs_fs_create(struct afs_server *server,
bool async)
{
struct afs_call *call;
struct afs_net *net = afs_v2net(vnode);
size_t namesz, reqsz, padsz;
__be32 *bp;
......@@ -708,7 +713,7 @@ int afs_fs_create(struct afs_server *server,
padsz = (4 - (namesz & 3)) & 3;
reqsz = (5 * 4) + namesz + padsz + (6 * 4);
call = afs_alloc_flat_call(&afs_RXFSCreateXXXX, reqsz,
call = afs_alloc_flat_call(net, &afs_RXFSCreateXXXX, reqsz,
(3 + 21 + 21 + 3 + 6) * 4);
if (!call)
return -ENOMEM;
......@@ -789,6 +794,7 @@ int afs_fs_remove(struct afs_server *server,
bool async)
{
struct afs_call *call;
struct afs_net *net = afs_v2net(vnode);
size_t namesz, reqsz, padsz;
__be32 *bp;
......@@ -798,7 +804,7 @@ int afs_fs_remove(struct afs_server *server,
padsz = (4 - (namesz & 3)) & 3;
reqsz = (5 * 4) + namesz + padsz;
call = afs_alloc_flat_call(&afs_RXFSRemoveXXXX, reqsz, (21 + 6) * 4);
call = afs_alloc_flat_call(net, &afs_RXFSRemoveXXXX, reqsz, (21 + 6) * 4);
if (!call)
return -ENOMEM;
......@@ -870,6 +876,7 @@ int afs_fs_link(struct afs_server *server,
bool async)
{
struct afs_call *call;
struct afs_net *net = afs_v2net(vnode);
size_t namesz, reqsz, padsz;
__be32 *bp;
......@@ -879,7 +886,7 @@ int afs_fs_link(struct afs_server *server,
padsz = (4 - (namesz & 3)) & 3;
reqsz = (5 * 4) + namesz + padsz + (3 * 4);
call = afs_alloc_flat_call(&afs_RXFSLink, reqsz, (21 + 21 + 6) * 4);
call = afs_alloc_flat_call(net, &afs_RXFSLink, reqsz, (21 + 21 + 6) * 4);
if (!call)
return -ENOMEM;
......@@ -958,6 +965,7 @@ int afs_fs_symlink(struct afs_server *server,
bool async)
{
struct afs_call *call;
struct afs_net *net = afs_v2net(vnode);
size_t namesz, reqsz, padsz, c_namesz, c_padsz;
__be32 *bp;
......@@ -971,7 +979,7 @@ int afs_fs_symlink(struct afs_server *server,
reqsz = (6 * 4) + namesz + padsz + c_namesz + c_padsz + (6 * 4);
call = afs_alloc_flat_call(&afs_RXFSSymlink, reqsz,
call = afs_alloc_flat_call(net, &afs_RXFSSymlink, reqsz,
(3 + 21 + 21 + 6) * 4);
if (!call)
return -ENOMEM;
......@@ -1062,6 +1070,7 @@ int afs_fs_rename(struct afs_server *server,
bool async)
{
struct afs_call *call;
struct afs_net *net = afs_v2net(orig_dvnode);
size_t reqsz, o_namesz, o_padsz, n_namesz, n_padsz;
__be32 *bp;
......@@ -1078,7 +1087,7 @@ int afs_fs_rename(struct afs_server *server,
(3 * 4) +
4 + n_namesz + n_padsz;
call = afs_alloc_flat_call(&afs_RXFSRename, reqsz, (21 + 21 + 6) * 4);
call = afs_alloc_flat_call(net, &afs_RXFSRename, reqsz, (21 + 21 + 6) * 4);
if (!call)
return -ENOMEM;
......@@ -1172,12 +1181,13 @@ static int afs_fs_store_data64(struct afs_server *server,
{
struct afs_vnode *vnode = wb->vnode;
struct afs_call *call;
struct afs_net *net = afs_v2net(vnode);
__be32 *bp;
_enter(",%x,{%x:%u},,",
key_serial(wb->key), vnode->fid.vid, vnode->fid.vnode);
call = afs_alloc_flat_call(&afs_RXFSStoreData64,
call = afs_alloc_flat_call(net, &afs_RXFSStoreData64,
(4 + 6 + 3 * 2) * 4,
(21 + 6) * 4);
if (!call)
......@@ -1230,6 +1240,7 @@ int afs_fs_store_data(struct afs_server *server, struct afs_writeback *wb,
{
struct afs_vnode *vnode = wb->vnode;
struct afs_call *call;
struct afs_net *net = afs_v2net(vnode);
loff_t size, pos, i_size;
__be32 *bp;
......@@ -1254,7 +1265,7 @@ int afs_fs_store_data(struct afs_server *server, struct afs_writeback *wb,
return afs_fs_store_data64(server, wb, first, last, offset, to,
size, pos, i_size, async);
call = afs_alloc_flat_call(&afs_RXFSStoreData,
call = afs_alloc_flat_call(net, &afs_RXFSStoreData,
(4 + 6 + 3) * 4,
(21 + 6) * 4);
if (!call)
......@@ -1356,6 +1367,7 @@ static int afs_fs_setattr_size64(struct afs_server *server, struct key *key,
bool async)
{
struct afs_call *call;
struct afs_net *net = afs_v2net(vnode);
__be32 *bp;
_enter(",%x,{%x:%u},,",
......@@ -1363,7 +1375,7 @@ static int afs_fs_setattr_size64(struct afs_server *server, struct key *key,
ASSERT(attr->ia_valid & ATTR_SIZE);
call = afs_alloc_flat_call(&afs_RXFSStoreData64_as_Status,
call = afs_alloc_flat_call(net, &afs_RXFSStoreData64_as_Status,
(4 + 6 + 3 * 2) * 4,
(21 + 6) * 4);
if (!call)
......@@ -1404,6 +1416,7 @@ static int afs_fs_setattr_size(struct afs_server *server, struct key *key,
bool async)
{
struct afs_call *call;
struct afs_net *net = afs_v2net(vnode);
__be32 *bp;
_enter(",%x,{%x:%u},,",
......@@ -1414,7 +1427,7 @@ static int afs_fs_setattr_size(struct afs_server *server, struct key *key,
return afs_fs_setattr_size64(server, key, vnode, attr,
async);
call = afs_alloc_flat_call(&afs_RXFSStoreData_as_Status,
call = afs_alloc_flat_call(net, &afs_RXFSStoreData_as_Status,
(4 + 6 + 3) * 4,
(21 + 6) * 4);
if (!call)
......@@ -1452,6 +1465,7 @@ int afs_fs_setattr(struct afs_server *server, struct key *key,
bool async)
{
struct afs_call *call;
struct afs_net *net = afs_v2net(vnode);
__be32 *bp;
if (attr->ia_valid & ATTR_SIZE)
......@@ -1461,7 +1475,7 @@ int afs_fs_setattr(struct afs_server *server, struct key *key,
_enter(",%x,{%x:%u},,",
key_serial(key), vnode->fid.vid, vnode->fid.vnode);
call = afs_alloc_flat_call(&afs_RXFSStoreStatus,
call = afs_alloc_flat_call(net, &afs_RXFSStoreStatus,
(4 + 6) * 4,
(21 + 6) * 4);
if (!call)
......@@ -1687,6 +1701,7 @@ int afs_fs_get_volume_status(struct afs_server *server,
bool async)
{
struct afs_call *call;
struct afs_net *net = afs_v2net(vnode);
__be32 *bp;
void *tmpbuf;
......@@ -1696,7 +1711,7 @@ int afs_fs_get_volume_status(struct afs_server *server,
if (!tmpbuf)
return -ENOMEM;
call = afs_alloc_flat_call(&afs_RXFSGetVolumeStatus, 2 * 4, 12 * 4);
call = afs_alloc_flat_call(net, &afs_RXFSGetVolumeStatus, 2 * 4, 12 * 4);
if (!call) {
kfree(tmpbuf);
return -ENOMEM;
......@@ -1779,11 +1794,12 @@ int afs_fs_set_lock(struct afs_server *server,
bool async)
{
struct afs_call *call;
struct afs_net *net = afs_v2net(vnode);
__be32 *bp;
_enter("");
call = afs_alloc_flat_call(&afs_RXFSSetLock, 5 * 4, 6 * 4);
call = afs_alloc_flat_call(net, &afs_RXFSSetLock, 5 * 4, 6 * 4);
if (!call)
return -ENOMEM;
......@@ -1812,11 +1828,12 @@ int afs_fs_extend_lock(struct afs_server *server,
bool async)
{
struct afs_call *call;
struct afs_net *net = afs_v2net(vnode);
__be32 *bp;
_enter("");
call = afs_alloc_flat_call(&afs_RXFSExtendLock, 4 * 4, 6 * 4);
call = afs_alloc_flat_call(net, &afs_RXFSExtendLock, 4 * 4, 6 * 4);
if (!call)
return -ENOMEM;
......@@ -1844,11 +1861,12 @@ int afs_fs_release_lock(struct afs_server *server,
bool async)
{
struct afs_call *call;
struct afs_net *net = afs_v2net(vnode);
__be32 *bp;
_enter("");
call = afs_alloc_flat_call(&afs_RXFSReleaseLock, 4 * 4, 6 * 4);
call = afs_alloc_flat_call(net, &afs_RXFSReleaseLock, 4 * 4, 6 * 4);
if (!call)
return -ENOMEM;
......
This diff is collapsed.
......@@ -31,30 +31,104 @@ static char *rootcell;
module_param(rootcell, charp, 0);
MODULE_PARM_DESC(rootcell, "root AFS cell name and VL server IP addr list");
struct afs_uuid afs_uuid;
struct workqueue_struct *afs_wq;
struct afs_net __afs_net;
/*
* Initialise an AFS network namespace record.
*/
static int __net_init afs_net_init(struct afs_net *net)
{
int ret;
net->live = true;
generate_random_uuid((unsigned char *)&net->uuid);
INIT_WORK(&net->charge_preallocation_work, afs_charge_preallocation);
mutex_init(&net->socket_mutex);
INIT_LIST_HEAD(&net->cells);
rwlock_init(&net->cells_lock);
init_rwsem(&net->cells_sem);
init_waitqueue_head(&net->cells_freeable_wq);
init_rwsem(&net->proc_cells_sem);
INIT_LIST_HEAD(&net->proc_cells);
INIT_LIST_HEAD(&net->vl_updates);
INIT_LIST_HEAD(&net->vl_graveyard);
INIT_DELAYED_WORK(&net->vl_reaper, afs_vlocation_reaper);
INIT_DELAYED_WORK(&net->vl_updater, afs_vlocation_updater);
spin_lock_init(&net->vl_updates_lock);
spin_lock_init(&net->vl_graveyard_lock);
net->servers = RB_ROOT;
rwlock_init(&net->servers_lock);
INIT_LIST_HEAD(&net->server_graveyard);
spin_lock_init(&net->server_graveyard_lock);
INIT_DELAYED_WORK(&net->server_reaper, afs_reap_server);
/* Register the /proc stuff */
ret = afs_proc_init(net);
if (ret < 0)
goto error_proc;
/* Initialise the cell DB */
ret = afs_cell_init(net, rootcell);
if (ret < 0)
goto error_cell_init;
/* Create the RxRPC transport */
ret = afs_open_socket(net);
if (ret < 0)
goto error_open_socket;
return 0;
error_open_socket:
afs_vlocation_purge(net);
afs_cell_purge(net);
error_cell_init:
afs_proc_cleanup(net);
error_proc:
return ret;
}
/*
* Clean up and destroy an AFS network namespace record.
*/
static void __net_exit afs_net_exit(struct afs_net *net)
{
net->live = false;
afs_close_socket(net);
afs_purge_servers(net);
afs_vlocation_purge(net);
afs_cell_purge(net);
afs_proc_cleanup(net);
}
/*
* initialise the AFS client FS module
*/
static int __init afs_init(void)
{
int ret;
int ret = -ENOMEM;
printk(KERN_INFO "kAFS: Red Hat AFS client v0.1 registering.\n");
generate_random_uuid((unsigned char *)&afs_uuid);
/* create workqueue */
ret = -ENOMEM;
afs_wq = alloc_workqueue("afs", 0, 0);
if (!afs_wq)
return ret;
/* register the /proc stuff */
ret = afs_proc_init();
if (ret < 0)
goto error_proc;
goto error_afs_wq;
afs_async_calls = alloc_workqueue("kafsd", WQ_MEM_RECLAIM, 0);
if (!afs_async_calls)
goto error_async;
afs_vlocation_update_worker =
alloc_workqueue("kafs_vlupdated", WQ_MEM_RECLAIM, 0);
if (!afs_vlocation_update_worker)
goto error_vl_up;
afs_callback_update_worker =
alloc_ordered_workqueue("kafs_callbackd", WQ_MEM_RECLAIM);
if (!afs_callback_update_worker)
goto error_callback;
afs_lock_manager = alloc_workqueue("kafs_lockd", WQ_MEM_RECLAIM, 0);
if (!afs_lock_manager)
goto error_lockmgr;
#ifdef CONFIG_AFS_FSCACHE
/* we want to be able to cache */
......@@ -63,25 +137,9 @@ static int __init afs_init(void)
goto error_cache;
#endif
/* initialise the cell DB */
ret = afs_cell_init(rootcell);
if (ret < 0)
goto error_cell_init;
/* initialise the VL update process */
ret = afs_vlocation_update_init();
if (ret < 0)
goto error_vl_update_init;
/* initialise the callback update process */
ret = afs_callback_update_init();
ret = afs_net_init(&__afs_net);
if (ret < 0)
goto error_callback_update_init;
/* create the RxRPC transport */
ret = afs_open_socket();
if (ret < 0)
goto error_open_socket;
goto error_net;
/* register the filesystems */
ret = afs_fs_init();
......@@ -91,21 +149,22 @@ static int __init afs_init(void)
return ret;
error_fs:
afs_close_socket();
error_open_socket:
afs_callback_update_kill();
error_callback_update_init:
afs_vlocation_purge();
error_vl_update_init:
afs_cell_purge();
error_cell_init:
afs_net_exit(&__afs_net);
error_net:
#ifdef CONFIG_AFS_FSCACHE
fscache_unregister_netfs(&afs_cache_netfs);
error_cache:
#endif
afs_proc_cleanup();
error_proc:
destroy_workqueue(afs_lock_manager);
error_lockmgr:
destroy_workqueue(afs_callback_update_worker);
error_callback:
destroy_workqueue(afs_vlocation_update_worker);
error_vl_up:
destroy_workqueue(afs_async_calls);
error_async:
destroy_workqueue(afs_wq);
error_afs_wq:
rcu_barrier();
printk(KERN_ERR "kAFS: failed to register: %d\n", ret);
return ret;
......@@ -124,17 +183,15 @@ static void __exit afs_exit(void)
printk(KERN_INFO "kAFS: Red Hat AFS client v0.1 unregistering.\n");
afs_fs_exit();
afs_kill_lock_manager();
afs_close_socket();
afs_purge_servers();
afs_callback_update_kill();
afs_vlocation_purge();
destroy_workqueue(afs_wq);
afs_cell_purge();
afs_net_exit(&__afs_net);
#ifdef CONFIG_AFS_FSCACHE
fscache_unregister_netfs(&afs_cache_netfs);
#endif
afs_proc_cleanup();
destroy_workqueue(afs_lock_manager);
destroy_workqueue(afs_callback_update_worker);
destroy_workqueue(afs_vlocation_update_worker);
destroy_workqueue(afs_async_calls);
destroy_workqueue(afs_wq);
rcu_barrier();
}
......
......@@ -17,8 +17,15 @@
#include <linux/uaccess.h>
#include "internal.h"
static struct proc_dir_entry *proc_afs;
static inline struct afs_net *afs_proc2net(struct file *f)
{
return &__afs_net;
}
static inline struct afs_net *afs_seq2net(struct seq_file *m)
{
return &__afs_net; // TODO: use seq_file_net(m)
}
static int afs_proc_cells_open(struct inode *inode, struct file *file);
static void *afs_proc_cells_start(struct seq_file *p, loff_t *pos);
......@@ -122,23 +129,23 @@ static const struct file_operations afs_proc_cell_servers_fops = {
/*
* initialise the /proc/fs/afs/ directory
*/
int afs_proc_init(void)
int afs_proc_init(struct afs_net *net)
{
_enter("");
proc_afs = proc_mkdir("fs/afs", NULL);
if (!proc_afs)
net->proc_afs = proc_mkdir("fs/afs", NULL);
if (!net->proc_afs)
goto error_dir;
if (!proc_create("cells", 0644, proc_afs, &afs_proc_cells_fops) ||
!proc_create("rootcell", 0644, proc_afs, &afs_proc_rootcell_fops))
if (!proc_create("cells", 0644, net->proc_afs, &afs_proc_cells_fops) ||
!proc_create("rootcell", 0644, net->proc_afs, &afs_proc_rootcell_fops))
goto error_tree;
_leave(" = 0");
return 0;
error_tree:
remove_proc_subtree("fs/afs", NULL);
proc_remove(net->proc_afs);
error_dir:
_leave(" = -ENOMEM");
return -ENOMEM;
......@@ -147,9 +154,10 @@ int afs_proc_init(void)
/*
* clean up the /proc/fs/afs/ directory
*/
void afs_proc_cleanup(void)
void afs_proc_cleanup(struct afs_net *net)
{
remove_proc_subtree("fs/afs", NULL);
proc_remove(net->proc_afs);
net->proc_afs = NULL;
}
/*
......@@ -176,25 +184,30 @@ static int afs_proc_cells_open(struct inode *inode, struct file *file)
*/
static void *afs_proc_cells_start(struct seq_file *m, loff_t *_pos)
{
/* lock the list against modification */
down_read(&afs_proc_cells_sem);
return seq_list_start_head(&afs_proc_cells, *_pos);
struct afs_net *net = afs_seq2net(m);
down_read(&net->proc_cells_sem);
return seq_list_start_head(&net->proc_cells, *_pos);
}
/*
* move to next cell in cells list
*/
static void *afs_proc_cells_next(struct seq_file *p, void *v, loff_t *pos)
static void *afs_proc_cells_next(struct seq_file *m, void *v, loff_t *pos)
{
return seq_list_next(v, &afs_proc_cells, pos);
struct afs_net *net = afs_seq2net(m);
return seq_list_next(v, &net->proc_cells, pos);
}
/*
* clean up after reading from the cells list
*/
static void afs_proc_cells_stop(struct seq_file *p, void *v)
static void afs_proc_cells_stop(struct seq_file *m, void *v)
{
up_read(&afs_proc_cells_sem);
struct afs_net *net = afs_seq2net(m);
up_read(&net->proc_cells_sem);
}
/*
......@@ -203,8 +216,9 @@ static void afs_proc_cells_stop(struct seq_file *p, void *v)
static int afs_proc_cells_show(struct seq_file *m, void *v)
{
struct afs_cell *cell = list_entry(v, struct afs_cell, proc_link);
struct afs_net *net = afs_seq2net(m);
if (v == &afs_proc_cells) {
if (v == &net->proc_cells) {
/* display header on line 1 */
seq_puts(m, "USE NAME\n");
return 0;
......@@ -223,6 +237,7 @@ static int afs_proc_cells_show(struct seq_file *m, void *v)
static ssize_t afs_proc_cells_write(struct file *file, const char __user *buf,
size_t size, loff_t *_pos)
{
struct afs_net *net = afs_proc2net(file);
char *kbuf, *name, *args;
int ret;
......@@ -264,7 +279,7 @@ static ssize_t afs_proc_cells_write(struct file *file, const char __user *buf,
if (strcmp(kbuf, "add") == 0) {
struct afs_cell *cell;
cell = afs_cell_create(name, strlen(name), args, false);
cell = afs_cell_create(net, name, strlen(name), args, false);
if (IS_ERR(cell)) {
ret = PTR_ERR(cell);
goto done;
......@@ -303,6 +318,7 @@ static ssize_t afs_proc_rootcell_write(struct file *file,
const char __user *buf,
size_t size, loff_t *_pos)
{
struct afs_net *net = afs_proc2net(file);
char *kbuf, *s;
int ret;
......@@ -322,7 +338,7 @@ static ssize_t afs_proc_rootcell_write(struct file *file,
/* determine command to perform */
_debug("rootcell=%s", kbuf);
ret = afs_cell_init(kbuf);
ret = afs_cell_init(net, kbuf);
if (ret >= 0)
ret = size; /* consume everything, always */
......@@ -334,13 +350,13 @@ static ssize_t afs_proc_rootcell_write(struct file *file,
/*
* initialise /proc/fs/afs/<cell>/
*/
int afs_proc_cell_setup(struct afs_cell *cell)
int afs_proc_cell_setup(struct afs_net *net, struct afs_cell *cell)
{
struct proc_dir_entry *dir;
_enter("%p{%s}", cell, cell->name);
dir = proc_mkdir(cell->name, proc_afs);
dir = proc_mkdir(cell->name, net->proc_afs);
if (!dir)
goto error_dir;
......@@ -356,7 +372,7 @@ int afs_proc_cell_setup(struct afs_cell *cell)
return 0;
error_tree:
remove_proc_subtree(cell->name, proc_afs);
remove_proc_subtree(cell->name, net->proc_afs);
error_dir:
_leave(" = -ENOMEM");
return -ENOMEM;
......@@ -365,11 +381,11 @@ int afs_proc_cell_setup(struct afs_cell *cell)
/*
* remove /proc/fs/afs/<cell>/
*/
void afs_proc_cell_remove(struct afs_cell *cell)
void afs_proc_cell_remove(struct afs_net *net, struct afs_cell *cell)
{
_enter("");
remove_proc_subtree(cell->name, proc_afs);
remove_proc_subtree(cell->name, net->proc_afs);
_leave("");
}
......
This diff is collapsed.
......@@ -15,32 +15,22 @@
static unsigned afs_server_timeout = 10; /* server timeout in seconds */
static void afs_reap_server(struct work_struct *);
/* tree of all the servers, indexed by IP address */
static struct rb_root afs_servers = RB_ROOT;
static DEFINE_RWLOCK(afs_servers_lock);
/* LRU list of all the servers not currently in use */
static LIST_HEAD(afs_server_graveyard);
static DEFINE_SPINLOCK(afs_server_graveyard_lock);
static DECLARE_DELAYED_WORK(afs_server_reaper, afs_reap_server);
/*
* install a server record in the master tree
*/
static int afs_install_server(struct afs_server *server)
{
struct afs_server *xserver;
struct afs_net *net = server->cell->net;
struct rb_node **pp, *p;
int ret;
_enter("%p", server);
write_lock(&afs_servers_lock);
write_lock(&net->servers_lock);
ret = -EEXIST;
pp = &afs_servers.rb_node;
pp = &net->servers.rb_node;
p = NULL;
while (*pp) {
p = *pp;
......@@ -55,11 +45,11 @@ static int afs_install_server(struct afs_server *server)
}
rb_link_node(&server->master_rb, p, pp);
rb_insert_color(&server->master_rb, &afs_servers);
rb_insert_color(&server->master_rb, &net->servers);
ret = 0;
error:
write_unlock(&afs_servers_lock);
write_unlock(&net->servers_lock);
return ret;
}
......@@ -150,9 +140,9 @@ struct afs_server *afs_lookup_server(struct afs_cell *cell,
read_unlock(&cell->servers_lock);
no_longer_unused:
if (!list_empty(&server->grave)) {
spin_lock(&afs_server_graveyard_lock);
spin_lock(&cell->net->server_graveyard_lock);
list_del_init(&server->grave);
spin_unlock(&afs_server_graveyard_lock);
spin_unlock(&cell->net->server_graveyard_lock);
}
_leave(" = %p{%d}", server, atomic_read(&server->usage));
return server;
......@@ -178,7 +168,8 @@ struct afs_server *afs_lookup_server(struct afs_cell *cell,
/*
* look up a server by its IP address
*/
struct afs_server *afs_find_server(const struct sockaddr_rxrpc *srx)
struct afs_server *afs_find_server(struct afs_net *net,
const struct sockaddr_rxrpc *srx)
{
struct afs_server *server = NULL;
struct rb_node *p;
......@@ -191,9 +182,9 @@ struct afs_server *afs_find_server(const struct sockaddr_rxrpc *srx)
return NULL;
}
read_lock(&afs_servers_lock);
read_lock(&net->servers_lock);
p = afs_servers.rb_node;
p = net->servers.rb_node;
while (p) {
server = rb_entry(p, struct afs_server, master_rb);
......@@ -211,7 +202,7 @@ struct afs_server *afs_find_server(const struct sockaddr_rxrpc *srx)
server = NULL;
found:
read_unlock(&afs_servers_lock);
read_unlock(&net->servers_lock);
ASSERTIFCMP(server, server->addr.s_addr, ==, addr.s_addr);
_leave(" = %p", server);
return server;
......@@ -223,6 +214,8 @@ struct afs_server *afs_find_server(const struct sockaddr_rxrpc *srx)
*/
void afs_put_server(struct afs_server *server)
{
struct afs_net *net = server->cell->net;
if (!server)
return;
......@@ -239,14 +232,14 @@ void afs_put_server(struct afs_server *server)
afs_flush_callback_breaks(server);
spin_lock(&afs_server_graveyard_lock);
spin_lock(&net->server_graveyard_lock);
if (atomic_read(&server->usage) == 0) {
list_move_tail(&server->grave, &afs_server_graveyard);
list_move_tail(&server->grave, &net->server_graveyard);
server->time_of_death = ktime_get_real_seconds();
queue_delayed_work(afs_wq, &afs_server_reaper,
afs_server_timeout * HZ);
queue_delayed_work(afs_wq, &net->server_reaper,
net->live ? afs_server_timeout * HZ : 0);
}
spin_unlock(&afs_server_graveyard_lock);
spin_unlock(&net->server_graveyard_lock);
_leave(" [dead]");
}
......@@ -272,42 +265,45 @@ static void afs_destroy_server(struct afs_server *server)
/*
* reap dead server records
*/
static void afs_reap_server(struct work_struct *work)
void afs_reap_server(struct work_struct *work)
{
LIST_HEAD(corpses);
struct afs_server *server;
struct afs_net *net = container_of(work, struct afs_net, server_reaper.work);
unsigned long delay, expiry;
time64_t now;
now = ktime_get_real_seconds();
spin_lock(&afs_server_graveyard_lock);
spin_lock(&net->server_graveyard_lock);
while (!list_empty(&afs_server_graveyard)) {
server = list_entry(afs_server_graveyard.next,
while (!list_empty(&net->server_graveyard)) {
server = list_entry(net->server_graveyard.next,
struct afs_server, grave);
/* the queue is ordered most dead first */
expiry = server->time_of_death + afs_server_timeout;
if (expiry > now) {
delay = (expiry - now) * HZ;
mod_delayed_work(afs_wq, &afs_server_reaper, delay);
break;
if (net->live) {
expiry = server->time_of_death + afs_server_timeout;
if (expiry > now) {
delay = (expiry - now) * HZ;
mod_delayed_work(afs_wq, &net->server_reaper, delay);
break;
}
}
write_lock(&server->cell->servers_lock);
write_lock(&afs_servers_lock);
write_lock(&net->servers_lock);
if (atomic_read(&server->usage) > 0) {
list_del_init(&server->grave);
} else {
list_move_tail(&server->grave, &corpses);
list_del_init(&server->link);
rb_erase(&server->master_rb, &afs_servers);
rb_erase(&server->master_rb, &net->servers);
}
write_unlock(&afs_servers_lock);
write_unlock(&net->servers_lock);
write_unlock(&server->cell->servers_lock);
}
spin_unlock(&afs_server_graveyard_lock);
spin_unlock(&net->server_graveyard_lock);
/* now reap the corpses we've extracted */
while (!list_empty(&corpses)) {
......@@ -318,10 +314,10 @@ static void afs_reap_server(struct work_struct *work)
}
/*
* discard all the server records for rmmod
* Discard all the server records from a net namespace when it is destroyed or
* the afs module is removed.
*/
void __exit afs_purge_servers(void)
void __net_exit afs_purge_servers(struct afs_net *net)
{
afs_server_timeout = 0;
mod_delayed_work(afs_wq, &afs_server_reaper, 0);
mod_delayed_work(afs_wq, &net->server_reaper, 0);
}
......@@ -25,11 +25,10 @@
#include <linux/statfs.h>
#include <linux/sched.h>
#include <linux/nsproxy.h>
#include <linux/magic.h>
#include <net/net_namespace.h>
#include "internal.h"
#define AFS_FS_MAGIC 0x6B414653 /* 'kAFS' */
static void afs_i_init_once(void *foo);
static struct dentry *afs_mount(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data);
......@@ -201,7 +200,8 @@ static int afs_parse_options(struct afs_mount_params *params,
token = match_token(p, afs_options_list, args);
switch (token) {
case afs_opt_cell:
cell = afs_cell_lookup(args[0].from,
cell = afs_cell_lookup(params->net,
args[0].from,
args[0].to - args[0].from,
false);
if (IS_ERR(cell))
......@@ -308,7 +308,7 @@ static int afs_parse_device_name(struct afs_mount_params *params,
/* lookup the cell record */
if (cellname || !params->cell) {
cell = afs_cell_lookup(cellname, cellnamesz, true);
cell = afs_cell_lookup(params->net, cellname, cellnamesz, true);
if (IS_ERR(cell)) {
printk(KERN_ERR "kAFS: unable to lookup cell '%*.*s'\n",
cellnamesz, cellnamesz, cellname ?: "");
......@@ -334,7 +334,7 @@ static int afs_test_super(struct super_block *sb, void *data)
struct afs_super_info *as1 = data;
struct afs_super_info *as = sb->s_fs_info;
return as->volume == as1->volume;
return as->net == as1->net && as->volume == as1->volume;
}
static int afs_set_super(struct super_block *sb, void *data)
......@@ -411,6 +411,7 @@ static struct dentry *afs_mount(struct file_system_type *fs_type,
_enter(",,%s,%p", dev_name, options);
memset(&params, 0, sizeof(params));
params.net = &__afs_net;
ret = -EINVAL;
if (current->nsproxy->net_ns != &init_net)
......@@ -444,36 +445,32 @@ static struct dentry *afs_mount(struct file_system_type *fs_type,
}
/* allocate a superblock info record */
ret = -ENOMEM;
as = kzalloc(sizeof(struct afs_super_info), GFP_KERNEL);
if (!as) {
ret = -ENOMEM;
afs_put_volume(vol);
goto error;
}
if (!as)
goto error_vol;
as->net = afs_get_net(params.net);
as->volume = vol;
/* allocate a deviceless superblock */
sb = sget(fs_type, afs_test_super, afs_set_super, flags, as);
if (IS_ERR(sb)) {
ret = PTR_ERR(sb);
afs_put_volume(vol);
kfree(as);
goto error;
goto error_as;
}
if (!sb->s_root) {
/* initial superblock/root creation */
_debug("create");
ret = afs_fill_super(sb, &params);
if (ret < 0) {
deactivate_locked_super(sb);
goto error;
}
if (ret < 0)
goto error_sb;
sb->s_flags |= MS_ACTIVE;
} else {
_debug("reuse");
ASSERTCMP(sb->s_flags, &, MS_ACTIVE);
afs_put_volume(vol);
afs_put_volume(params.net, vol);
kfree(as);
}
......@@ -482,6 +479,14 @@ static struct dentry *afs_mount(struct file_system_type *fs_type,
_leave(" = 0 [%p]", sb);
return dget(sb->s_root);
error_sb:
deactivate_locked_super(sb);
goto error;
error_as:
afs_put_net(as->net);
kfree(as);
error_vol:
afs_put_volume(params.net, vol);
error:
afs_put_cell(params.cell);
key_put(params.key);
......@@ -493,8 +498,10 @@ static struct dentry *afs_mount(struct file_system_type *fs_type,
static void afs_kill_super(struct super_block *sb)
{
struct afs_super_info *as = sb->s_fs_info;
struct afs_net *net = as->net;
kill_anon_super(sb);
afs_put_volume(as->volume);
afs_put_volume(net, as->volume);
kfree(as);
}
......
......@@ -143,7 +143,8 @@ static const struct afs_call_type afs_RXVLGetEntryById = {
/*
* dispatch a get volume entry by name operation
*/
int afs_vl_get_entry_by_name(struct in_addr *addr,
int afs_vl_get_entry_by_name(struct afs_net *net,
struct in_addr *addr,
struct key *key,
const char *volname,
struct afs_cache_vlocation *entry,
......@@ -159,7 +160,7 @@ int afs_vl_get_entry_by_name(struct in_addr *addr,
padsz = (4 - (volnamesz & 3)) & 3;
reqsz = 8 + volnamesz + padsz;
call = afs_alloc_flat_call(&afs_RXVLGetEntryByName, reqsz, 384);
call = afs_alloc_flat_call(net, &afs_RXVLGetEntryByName, reqsz, 384);
if (!call)
return -ENOMEM;
......@@ -183,7 +184,8 @@ int afs_vl_get_entry_by_name(struct in_addr *addr,
/*
* dispatch a get volume entry by ID operation
*/
int afs_vl_get_entry_by_id(struct in_addr *addr,
int afs_vl_get_entry_by_id(struct afs_net *net,
struct in_addr *addr,
struct key *key,
afs_volid_t volid,
afs_voltype_t voltype,
......@@ -195,7 +197,7 @@ int afs_vl_get_entry_by_id(struct in_addr *addr,
_enter("");
call = afs_alloc_flat_call(&afs_RXVLGetEntryById, 12, 384);
call = afs_alloc_flat_call(net, &afs_RXVLGetEntryById, 12, 384);
if (!call)
return -ENOMEM;
......
This diff is collapsed.
......@@ -54,7 +54,7 @@ struct afs_volume *afs_volume_lookup(struct afs_mount_params *params)
params->volnamesz, params->volnamesz, params->volname, params->rwpath);
/* lookup the volume location record */
vlocation = afs_vlocation_lookup(params->cell, params->key,
vlocation = afs_vlocation_lookup(params->net, params->cell, params->key,
params->volname, params->volnamesz);
if (IS_ERR(vlocation)) {
ret = PTR_ERR(vlocation);
......@@ -138,7 +138,7 @@ struct afs_volume *afs_volume_lookup(struct afs_mount_params *params)
_debug("kAFS selected %s volume %08x",
afs_voltypes[volume->type], volume->vid);
up_write(&params->cell->vl_sem);
afs_put_vlocation(vlocation);
afs_put_vlocation(params->net, vlocation);
_leave(" = %p", volume);
return volume;
......@@ -146,7 +146,7 @@ struct afs_volume *afs_volume_lookup(struct afs_mount_params *params)
error_up:
up_write(&params->cell->vl_sem);
error:
afs_put_vlocation(vlocation);
afs_put_vlocation(params->net, vlocation);
_leave(" = %d", ret);
return ERR_PTR(ret);
......@@ -163,7 +163,7 @@ struct afs_volume *afs_volume_lookup(struct afs_mount_params *params)
/*
* destroy a volume record
*/
void afs_put_volume(struct afs_volume *volume)
void afs_put_volume(struct afs_net *net, struct afs_volume *volume)
{
struct afs_vlocation *vlocation;
int loop;
......@@ -195,7 +195,7 @@ void afs_put_volume(struct afs_volume *volume)
#ifdef CONFIG_AFS_FSCACHE
fscache_relinquish_cookie(volume->cache, 0);
#endif
afs_put_vlocation(vlocation);
afs_put_vlocation(net, vlocation);
for (loop = volume->nservers - 1; loop >= 0; loop--)
afs_put_server(volume->servers[loop]);
......
......@@ -47,6 +47,7 @@
#define OPENPROM_SUPER_MAGIC 0x9fa1
#define QNX4_SUPER_MAGIC 0x002f /* qnx4 fs detection */
#define QNX6_SUPER_MAGIC 0x68191122 /* qnx6 fs detection */
#define AFS_FS_MAGIC 0x6B414653
#define REISERFS_SUPER_MAGIC 0x52654973 /* used by gcc */
/* used by file system utilities that
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment