2007-04-27 02:49:28 +04:00
/* AFS cell and server record management
2005-04-17 02:20:36 +04:00
*
* Copyright ( C ) 2002 Red Hat , Inc . All Rights Reserved .
* Written by David Howells ( dhowells @ redhat . com )
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version
* 2 of the License , or ( at your option ) any later version .
*/
# include <linux/module.h>
# include <linux/slab.h>
2007-04-27 02:57:07 +04:00
# include <linux/key.h>
# include <linux/ctype.h>
Detach sched.h from mm.h
First thing mm.h does is including sched.h solely for can_do_mlock() inline
function which has "current" dereference inside. By dealing with can_do_mlock()
mm.h can be detached from sched.h which is good. See below, why.
This patch
a) removes unconditional inclusion of sched.h from mm.h
b) makes can_do_mlock() normal function in mm/mlock.c
c) exports can_do_mlock() to not break compilation
d) adds sched.h inclusions back to files that were getting it indirectly.
e) adds less bloated headers to some files (asm/signal.h, jiffies.h) that were
getting them indirectly
Net result is:
a) mm.h users would get less code to open, read, preprocess, parse, ... if
they don't need sched.h
b) sched.h stops being dependency for significant number of files:
on x86_64 allmodconfig touching sched.h results in recompile of 4083 files,
after patch it's only 3744 (-8.3%).
Cross-compile tested on
all arm defconfigs, all mips defconfigs, all powerpc defconfigs,
alpha alpha-up
arm
i386 i386-up i386-defconfig i386-allnoconfig
ia64 ia64-up
m68k
mips
parisc parisc-up
powerpc powerpc-up
s390 s390-up
sparc sparc-up
sparc64 sparc64-up
um-x86_64
x86_64 x86_64-up x86_64-defconfig x86_64-allnoconfig
as well as my two usual configs.
Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-05-21 01:22:52 +04:00
# include <linux/sched.h>
2007-04-27 02:57:07 +04:00
# include <keys/rxrpc-type.h>
2005-04-17 02:20:36 +04:00
# include "internal.h"
DECLARE_RWSEM ( afs_proc_cells_sem ) ;
LIST_HEAD ( afs_proc_cells ) ;
2008-04-29 12:03:20 +04:00
static LIST_HEAD ( afs_cells ) ;
2005-04-17 02:20:36 +04:00
static DEFINE_RWLOCK ( afs_cells_lock ) ;
static DECLARE_RWSEM ( afs_cells_sem ) ; /* add/remove serialisation */
2007-04-27 02:55:03 +04:00
static DECLARE_WAIT_QUEUE_HEAD ( afs_cells_freeable_wq ) ;
2005-04-17 02:20:36 +04:00
static struct afs_cell * afs_cell_root ;
/*
2007-04-27 02:57:07 +04:00
* allocate a cell record and fill in its name , VL server address list and
* allocate an anonymous key
2005-04-17 02:20:36 +04:00
*/
2007-04-27 02:57:07 +04:00
static struct afs_cell * afs_cell_alloc ( const char * name , char * vllist )
2005-04-17 02:20:36 +04:00
{
struct afs_cell * cell ;
2007-10-17 10:29:46 +04:00
struct key * key ;
2007-04-27 02:57:07 +04:00
size_t namelen ;
char keyname [ 4 + AFS_MAXCELLNAME + 1 ] , * cp , * dp , * next ;
2005-04-17 02:20:36 +04:00
int ret ;
2007-04-27 02:55:03 +04:00
_enter ( " %s,%s " , name , vllist ) ;
2005-04-17 02:20:36 +04:00
BUG_ON ( ! name ) ; /* TODO: want to look up "this cell" in the cache */
2007-04-27 02:57:07 +04:00
namelen = strlen ( name ) ;
if ( namelen > AFS_MAXCELLNAME )
return ERR_PTR ( - ENAMETOOLONG ) ;
2005-04-17 02:20:36 +04:00
/* allocate and initialise a cell record */
2007-04-27 02:57:07 +04:00
cell = kzalloc ( sizeof ( struct afs_cell ) + namelen + 1 , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( ! cell ) {
_leave ( " = -ENOMEM " ) ;
2007-04-27 02:55:03 +04:00
return ERR_PTR ( - ENOMEM ) ;
2005-04-17 02:20:36 +04:00
}
2007-04-27 02:57:07 +04:00
memcpy ( cell - > name , name , namelen ) ;
cell - > name [ namelen ] = 0 ;
2005-04-17 02:20:36 +04:00
2007-04-27 02:55:03 +04:00
atomic_set ( & cell - > usage , 1 ) ;
2005-04-17 02:20:36 +04:00
INIT_LIST_HEAD ( & cell - > link ) ;
2007-04-27 02:55:03 +04:00
rwlock_init ( & cell - > servers_lock ) ;
INIT_LIST_HEAD ( & cell - > servers ) ;
2005-04-17 02:20:36 +04:00
init_rwsem ( & cell - > vl_sem ) ;
INIT_LIST_HEAD ( & cell - > vl_list ) ;
2007-04-27 02:55:03 +04:00
spin_lock_init ( & cell - > vl_lock ) ;
2005-04-17 02:20:36 +04:00
/* fill in the VL server list from the rest of the string */
do {
unsigned a , b , c , d ;
next = strchr ( vllist , ' : ' ) ;
if ( next )
* next + + = 0 ;
if ( sscanf ( vllist , " %u.%u.%u.%u " , & a , & b , & c , & d ) ! = 4 )
2007-04-27 02:57:07 +04:00
goto bad_address ;
2005-04-17 02:20:36 +04:00
if ( a > 255 | | b > 255 | | c > 255 | | d > 255 )
2007-04-27 02:57:07 +04:00
goto bad_address ;
2005-04-17 02:20:36 +04:00
cell - > vl_addrs [ cell - > vl_naddrs + + ] . s_addr =
htonl ( ( a < < 24 ) | ( b < < 16 ) | ( c < < 8 ) | d ) ;
2007-04-27 02:57:07 +04:00
} while ( cell - > vl_naddrs < AFS_CELL_MAX_ADDRS & & ( vllist = next ) ) ;
/* create a key to represent an anonymous user */
memcpy ( keyname , " afs@ " , 4 ) ;
dp = keyname + 4 ;
cp = cell - > name ;
do {
* dp + + = toupper ( * cp ) ;
} while ( * cp + + ) ;
2007-10-17 10:29:46 +04:00
key = rxrpc_get_null_key ( keyname ) ;
if ( IS_ERR ( key ) ) {
_debug ( " no key " ) ;
ret = PTR_ERR ( key ) ;
2007-04-27 02:57:07 +04:00
goto error ;
}
2007-10-17 10:29:46 +04:00
cell - > anonymous_key = key ;
2007-04-27 02:57:07 +04:00
_debug ( " anon key %p{%x} " ,
cell - > anonymous_key , key_serial ( cell - > anonymous_key ) ) ;
_leave ( " = %p " , cell ) ;
return cell ;
bad_address :
printk ( KERN_ERR " kAFS: bad VL server IP address \n " ) ;
ret = - EINVAL ;
error :
key_put ( cell - > anonymous_key ) ;
kfree ( cell ) ;
_leave ( " = %d " , ret ) ;
return ERR_PTR ( ret ) ;
}
2005-04-17 02:20:36 +04:00
2007-04-27 02:57:07 +04:00
/*
* create a cell record
* - " name " is the name of the cell
* - " vllist " is a colon separated list of IP addresses in " a.b.c.d " format
*/
struct afs_cell * afs_cell_create ( const char * name , char * vllist )
{
struct afs_cell * cell ;
int ret ;
_enter ( " %s,%s " , name , vllist ) ;
2008-03-29 00:15:55 +03:00
down_write ( & afs_cells_sem ) ;
read_lock ( & afs_cells_lock ) ;
list_for_each_entry ( cell , & afs_cells , link ) {
if ( strcasecmp ( cell - > name , name ) = = 0 )
goto duplicate_name ;
}
read_unlock ( & afs_cells_lock ) ;
2007-04-27 02:57:07 +04:00
cell = afs_cell_alloc ( name , vllist ) ;
if ( IS_ERR ( cell ) ) {
_leave ( " = %ld " , PTR_ERR ( cell ) ) ;
2008-04-02 16:17:18 +04:00
up_write ( & afs_cells_sem ) ;
2007-04-27 02:57:07 +04:00
return cell ;
}
2007-04-27 02:55:03 +04:00
/* add a proc directory for this cell */
2005-04-17 02:20:36 +04:00
ret = afs_proc_cell_setup ( cell ) ;
if ( ret < 0 )
goto error ;
2009-04-03 19:42:41 +04:00
# ifdef CONFIG_AFS_FSCACHE
/* put it up for caching (this never returns an error) */
cell - > cache = fscache_acquire_cookie ( afs_cache_netfs . primary_index ,
& afs_cell_cache_index_def ,
cell ) ;
2005-04-17 02:20:36 +04:00
# endif
/* add to the cell lists */
write_lock ( & afs_cells_lock ) ;
list_add_tail ( & cell - > link , & afs_cells ) ;
write_unlock ( & afs_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 ) ;
2007-04-27 02:55:03 +04:00
_leave ( " = %p " , cell ) ;
return cell ;
2005-04-17 02:20:36 +04:00
2007-04-27 02:49:28 +04:00
error :
2005-04-17 02:20:36 +04:00
up_write ( & afs_cells_sem ) ;
2007-04-27 02:57:07 +04:00
key_put ( cell - > anonymous_key ) ;
2005-04-17 02:20:36 +04:00
kfree ( cell ) ;
_leave ( " = %d " , ret ) ;
2007-04-27 02:55:03 +04:00
return ERR_PTR ( ret ) ;
2008-03-29 00:15:55 +03:00
duplicate_name :
read_unlock ( & afs_cells_lock ) ;
up_write ( & afs_cells_sem ) ;
return ERR_PTR ( - EEXIST ) ;
2007-04-27 02:49:28 +04:00
}
2005-04-17 02:20:36 +04:00
/*
2007-04-27 02:55:03 +04:00
* set the root cell information
* - can be called with a module parameter string
* - can be called from a write to / proc / fs / afs / rootcell
2005-04-17 02:20:36 +04:00
*/
int afs_cell_init ( char * rootcell )
{
struct afs_cell * old_root , * new_root ;
char * cp ;
_enter ( " " ) ;
if ( ! rootcell ) {
/* module is loaded with no parameters, or built statically.
* - in the future we might initialize cell DB here .
*/
2007-04-27 02:55:03 +04:00
_leave ( " = 0 [no root] " ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
cp = strchr ( rootcell , ' : ' ) ;
if ( ! cp ) {
printk ( KERN_ERR " kAFS: no VL server IP addresses specified \n " ) ;
2007-04-27 02:55:03 +04:00
_leave ( " = -EINVAL " ) ;
2005-04-17 02:20:36 +04:00
return - EINVAL ;
}
/* allocate a cell record for the root cell */
* cp + + = 0 ;
2007-04-27 02:55:03 +04:00
new_root = afs_cell_create ( rootcell , cp ) ;
if ( IS_ERR ( new_root ) ) {
_leave ( " = %ld " , PTR_ERR ( new_root ) ) ;
return PTR_ERR ( new_root ) ;
2005-04-17 02:20:36 +04:00
}
2007-04-27 02:55:03 +04:00
/* install the new cell */
2005-04-17 02:20:36 +04:00
write_lock ( & afs_cells_lock ) ;
2007-04-27 02:55:03 +04:00
old_root = afs_cell_root ;
2005-04-17 02:20:36 +04:00
afs_cell_root = new_root ;
write_unlock ( & afs_cells_lock ) ;
2007-04-27 02:55:03 +04:00
afs_put_cell ( old_root ) ;
2005-04-17 02:20:36 +04:00
2007-04-27 02:55:03 +04:00
_leave ( " = 0 " ) ;
return 0 ;
2007-04-27 02:49:28 +04:00
}
2005-04-17 02:20:36 +04:00
/*
* lookup a cell record
*/
2007-04-27 02:55:03 +04:00
struct afs_cell * afs_cell_lookup ( const char * name , unsigned namesz )
2005-04-17 02:20:36 +04:00
{
struct afs_cell * cell ;
_enter ( " \" %*.*s \" , " , namesz , namesz , name ? name : " " ) ;
2007-04-27 02:55:03 +04:00
down_read ( & afs_cells_sem ) ;
read_lock ( & afs_cells_lock ) ;
2005-04-17 02:20:36 +04:00
if ( name ) {
/* if the cell was named, look for it in the cell record list */
list_for_each_entry ( cell , & afs_cells , link ) {
if ( strncmp ( cell - > name , name , namesz ) = = 0 ) {
afs_get_cell ( cell ) ;
goto found ;
}
}
2007-04-27 02:55:03 +04:00
cell = ERR_PTR ( - ENOENT ) ;
2005-04-17 02:20:36 +04:00
found :
2007-04-27 02:55:03 +04:00
;
2007-04-27 02:49:28 +04:00
} else {
2005-04-17 02:20:36 +04:00
cell = afs_cell_root ;
if ( ! cell ) {
/* this should not happen unless user tries to mount
* when root cell is not set . Return an impossibly
* bizzare errno to alert the user . Things like
* ENOENT might be " more appropriate " but they happen
* for other reasons .
*/
2007-04-27 02:55:03 +04:00
cell = ERR_PTR ( - EDESTADDRREQ ) ;
2007-04-27 02:49:28 +04:00
} else {
2005-04-17 02:20:36 +04:00
afs_get_cell ( cell ) ;
}
}
2007-04-27 02:55:03 +04:00
read_unlock ( & afs_cells_lock ) ;
up_read ( & afs_cells_sem ) ;
_leave ( " = %p " , cell ) ;
return cell ;
2007-04-27 02:49:28 +04:00
}
2005-04-17 02:20:36 +04:00
2007-10-17 10:26:41 +04:00
#if 0
2005-04-17 02:20:36 +04:00
/*
* try and get a cell record
*/
2007-04-27 02:55:03 +04:00
struct afs_cell * afs_get_cell_maybe ( struct afs_cell * cell )
2005-04-17 02:20:36 +04:00
{
write_lock ( & afs_cells_lock ) ;
if ( cell & & ! list_empty ( & cell - > link ) )
afs_get_cell ( cell ) ;
else
cell = NULL ;
write_unlock ( & afs_cells_lock ) ;
return cell ;
2007-04-27 02:49:28 +04:00
}
2007-10-17 10:26:41 +04:00
# endif /* 0 */
2005-04-17 02:20:36 +04:00
/*
* destroy a cell record
*/
void afs_put_cell ( struct afs_cell * cell )
{
if ( ! cell )
return ;
_enter ( " %p{%d,%s} " , cell , atomic_read ( & cell - > usage ) , cell - > name ) ;
2007-04-27 02:55:03 +04:00
ASSERTCMP ( atomic_read ( & cell - > usage ) , > , 0 ) ;
2005-04-17 02:20:36 +04:00
/* to prevent a race, the decrement and the dequeue must be effectively
* atomic */
write_lock ( & afs_cells_lock ) ;
if ( likely ( ! atomic_dec_and_test ( & cell - > usage ) ) ) {
write_unlock ( & afs_cells_lock ) ;
_leave ( " " ) ;
return ;
}
2007-04-27 02:55:03 +04:00
ASSERT ( list_empty ( & cell - > servers ) ) ;
ASSERT ( list_empty ( & cell - > vl_list ) ) ;
2005-04-17 02:20:36 +04:00
write_unlock ( & afs_cells_lock ) ;
2007-04-27 02:55:03 +04:00
wake_up ( & afs_cells_freeable_wq ) ;
2005-04-17 02:20:36 +04:00
_leave ( " [unused] " ) ;
2007-04-27 02:49:28 +04:00
}
2005-04-17 02:20:36 +04:00
/*
* destroy a cell record
2007-04-27 02:55:03 +04:00
* - must be called with the afs_cells_sem write - locked
* - cell - > link should have been broken by the caller
2005-04-17 02:20:36 +04:00
*/
static void afs_cell_destroy ( struct afs_cell * cell )
{
_enter ( " %p{%d,%s} " , cell , atomic_read ( & cell - > usage ) , cell - > name ) ;
2007-04-27 02:55:03 +04:00
ASSERTCMP ( atomic_read ( & cell - > usage ) , > = , 0 ) ;
ASSERT ( list_empty ( & cell - > link ) ) ;
2005-04-17 02:20:36 +04:00
2007-04-27 02:55:03 +04:00
/* wait for everyone to stop using the cell */
if ( atomic_read ( & cell - > usage ) > 0 ) {
DECLARE_WAITQUEUE ( myself , current ) ;
2005-04-17 02:20:36 +04:00
2007-04-27 02:55:03 +04:00
_debug ( " wait for cell %s " , cell - > name ) ;
set_current_state ( TASK_UNINTERRUPTIBLE ) ;
add_wait_queue ( & afs_cells_freeable_wq , & myself ) ;
2005-04-17 02:20:36 +04:00
2007-04-27 02:55:03 +04:00
while ( atomic_read ( & cell - > usage ) > 0 ) {
schedule ( ) ;
set_current_state ( TASK_UNINTERRUPTIBLE ) ;
}
2005-04-17 02:20:36 +04:00
2007-04-27 02:55:03 +04:00
remove_wait_queue ( & afs_cells_freeable_wq , & myself ) ;
set_current_state ( TASK_RUNNING ) ;
}
_debug ( " cell dead " ) ;
ASSERTCMP ( atomic_read ( & cell - > usage ) , = = , 0 ) ;
ASSERT ( list_empty ( & cell - > servers ) ) ;
ASSERT ( list_empty ( & cell - > vl_list ) ) ;
2005-04-17 02:20:36 +04:00
afs_proc_cell_remove ( cell ) ;
down_write ( & afs_proc_cells_sem ) ;
list_del_init ( & cell - > proc_link ) ;
up_write ( & afs_proc_cells_sem ) ;
2009-04-03 19:42:41 +04:00
# ifdef CONFIG_AFS_FSCACHE
fscache_relinquish_cookie ( cell - > cache , 0 ) ;
2005-04-17 02:20:36 +04:00
# endif
2007-04-27 02:57:07 +04:00
key_put ( cell - > anonymous_key ) ;
2005-04-17 02:20:36 +04:00
kfree ( cell ) ;
_leave ( " [destroyed] " ) ;
2007-04-27 02:49:28 +04:00
}
2005-04-17 02:20:36 +04:00
/*
* 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 )
{
struct afs_cell * cell ;
_enter ( " " ) ;
afs_put_cell ( afs_cell_root ) ;
2007-04-27 02:55:03 +04:00
down_write ( & afs_cells_sem ) ;
2005-04-17 02:20:36 +04:00
while ( ! list_empty ( & afs_cells ) ) {
cell = NULL ;
/* remove the next cell from the front of the list */
write_lock ( & afs_cells_lock ) ;
if ( ! list_empty ( & afs_cells ) ) {
cell = list_entry ( afs_cells . next ,
struct afs_cell , link ) ;
list_del_init ( & cell - > link ) ;
}
write_unlock ( & afs_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 ) ;
}
}
2007-04-27 02:55:03 +04:00
up_write ( & afs_cells_sem ) ;
2005-04-17 02:20:36 +04:00
_leave ( " " ) ;
2007-04-27 02:49:28 +04:00
}