2010-10-20 00:18:04 -04:00
/*
* Device operations for the pnfs nfs4 file layout driver .
*
* Copyright ( c ) 2002
* The Regents of the University of Michigan
* All Rights Reserved
*
* Dean Hildebrand < dhildebz @ umich . edu >
* Garth Goodson < Garth . Goodson @ netapp . com >
*
* Permission is granted to use , copy , create derivative works , and
* redistribute this software and such derivative works for any purpose ,
* so long as the name of the University of Michigan is not used in
* any advertising or publicity pertaining to the use or distribution
* of this software without specific , written prior authorization . If
* the above copyright notice or any other identification of the
* University of Michigan is included in any copy of any portion of
* this software , then the disclaimer below must also be included .
*
* This software is provided as is , without representation or warranty
* of any kind either express or implied , including without limitation
* the implied warranties of merchantability , fitness for a particular
* purpose , or noninfringement . The Regents of the University of
* Michigan shall not be liable for any damages , including special ,
* indirect , incidental , or consequential damages , with respect to any
* claim arising out of or in connection with the use of the software ,
* even if it has been or is hereafter advised of the possibility of
* such damages .
*/
# include <linux/nfs_fs.h>
# include <linux/vmalloc.h>
2012-04-27 17:53:45 -04:00
# include <linux/module.h>
2010-10-20 00:18:04 -04:00
2014-05-12 14:35:52 -07:00
# include "../internal.h"
# include "../nfs4session.h"
# include "filelayout.h"
2010-10-20 00:18:04 -04:00
# define NFSDBG_FACILITY NFSDBG_PNFS_LD
2012-04-27 17:53:45 -04:00
static unsigned int dataserver_timeo = NFS4_DEF_DS_TIMEO ;
static unsigned int dataserver_retrans = NFS4_DEF_DS_RETRANS ;
2011-05-20 13:47:33 +02:00
void
2010-10-20 00:18:04 -04:00
nfs4_fl_free_deviceid ( struct nfs4_file_layout_dsaddr * dsaddr )
{
struct nfs4_pnfs_ds * ds ;
int i ;
2011-05-19 22:14:47 -04:00
nfs4_print_deviceid ( & dsaddr - > id_node . deviceid ) ;
2010-10-20 00:18:04 -04:00
for ( i = 0 ; i < dsaddr - > ds_num ; i + + ) {
ds = dsaddr - > ds_list [ i ] ;
2014-05-29 21:06:57 +08:00
if ( ds ! = NULL )
nfs4_pnfs_ds_put ( ds ) ;
2010-10-20 00:18:04 -04:00
}
kfree ( dsaddr - > stripe_indices ) ;
2015-03-09 15:23:35 -04:00
kfree_rcu ( dsaddr , id_node . rcu ) ;
2010-10-20 00:18:04 -04:00
}
/* Decode opaque device data and return the result */
2014-09-02 21:27:57 -07:00
struct nfs4_file_layout_dsaddr *
nfs4_fl_alloc_deviceid_node ( struct nfs_server * server , struct pnfs_device * pdev ,
gfp_t gfp_flags )
2010-10-20 00:18:04 -04:00
{
2011-03-24 16:48:21 -04:00
int i ;
2010-10-20 00:18:04 -04:00
u32 cnt , num ;
u8 * indexp ;
2011-03-24 16:48:21 -04:00
__be32 * p ;
u8 * stripe_indices ;
u8 max_stripe_index ;
struct nfs4_file_layout_dsaddr * dsaddr = NULL ;
struct xdr_stream stream ;
2011-05-19 14:16:47 -04:00
struct xdr_buf buf ;
2011-03-24 16:48:21 -04:00
struct page * scratch ;
2011-05-31 18:48:57 -04:00
struct list_head dsaddrs ;
struct nfs4_pnfs_ds_addr * da ;
2011-03-24 16:48:21 -04:00
/* set up xdr stream */
2011-05-11 18:00:51 -04:00
scratch = alloc_page ( gfp_flags ) ;
2011-03-24 16:48:21 -04:00
if ( ! scratch )
goto out_err ;
2011-05-19 14:16:47 -04:00
xdr_init_decode_pages ( & stream , & buf , pdev - > pages , pdev - > pglen ) ;
2011-03-24 16:48:21 -04:00
xdr_set_scratch_buffer ( & stream , page_address ( scratch ) , PAGE_SIZE ) ;
2010-10-20 00:18:04 -04:00
/* Get the stripe count (number of stripe index) */
2011-03-24 16:48:21 -04:00
p = xdr_inline_decode ( & stream , 4 ) ;
if ( unlikely ( ! p ) )
goto out_err_free_scratch ;
cnt = be32_to_cpup ( p ) ;
2010-10-20 00:18:04 -04:00
dprintk ( " %s stripe count %d \n " , __func__ , cnt ) ;
if ( cnt > NFS4_PNFS_MAX_STRIPE_CNT ) {
2012-01-26 13:32:23 -05:00
printk ( KERN_WARNING " NFS: %s: stripe count %d greater than "
2010-10-20 00:18:04 -04:00
" supported maximum %d \n " , __func__ ,
cnt , NFS4_PNFS_MAX_STRIPE_CNT ) ;
2011-03-24 16:48:21 -04:00
goto out_err_free_scratch ;
}
/* read stripe indices */
2011-05-11 18:00:51 -04:00
stripe_indices = kcalloc ( cnt , sizeof ( u8 ) , gfp_flags ) ;
2011-03-24 16:48:21 -04:00
if ( ! stripe_indices )
goto out_err_free_scratch ;
p = xdr_inline_decode ( & stream , cnt < < 2 ) ;
if ( unlikely ( ! p ) )
goto out_err_free_stripe_indices ;
indexp = & stripe_indices [ 0 ] ;
max_stripe_index = 0 ;
for ( i = 0 ; i < cnt ; i + + ) {
* indexp = be32_to_cpup ( p + + ) ;
max_stripe_index = max ( max_stripe_index , * indexp ) ;
indexp + + ;
2010-10-20 00:18:04 -04:00
}
/* Check the multipath list count */
2011-03-24 16:48:21 -04:00
p = xdr_inline_decode ( & stream , 4 ) ;
if ( unlikely ( ! p ) )
goto out_err_free_stripe_indices ;
num = be32_to_cpup ( p ) ;
2010-10-20 00:18:04 -04:00
dprintk ( " %s ds_num %u \n " , __func__ , num ) ;
if ( num > NFS4_PNFS_MAX_MULTI_CNT ) {
2012-01-26 13:32:23 -05:00
printk ( KERN_WARNING " NFS: %s: multipath count %d greater than "
2010-10-20 00:18:04 -04:00
" supported maximum %d \n " , __func__ ,
num , NFS4_PNFS_MAX_MULTI_CNT ) ;
2011-03-24 16:48:21 -04:00
goto out_err_free_stripe_indices ;
2010-10-20 00:18:04 -04:00
}
2011-03-24 16:48:21 -04:00
/* validate stripe indices are all < num */
if ( max_stripe_index > = num ) {
2012-01-26 13:32:23 -05:00
printk ( KERN_WARNING " NFS: %s: stripe index %u >= num ds %u \n " ,
2011-03-24 16:48:21 -04:00
__func__ , max_stripe_index , num ) ;
goto out_err_free_stripe_indices ;
}
2010-10-20 00:18:04 -04:00
dsaddr = kzalloc ( sizeof ( * dsaddr ) +
( sizeof ( struct nfs4_pnfs_ds * ) * ( num - 1 ) ) ,
2011-05-11 18:00:51 -04:00
gfp_flags ) ;
2010-10-20 00:18:04 -04:00
if ( ! dsaddr )
2011-03-24 16:48:21 -04:00
goto out_err_free_stripe_indices ;
2010-10-20 00:18:04 -04:00
dsaddr - > stripe_count = cnt ;
2011-03-24 16:48:21 -04:00
dsaddr - > stripe_indices = stripe_indices ;
stripe_indices = NULL ;
2010-10-20 00:18:04 -04:00
dsaddr - > ds_num = num ;
2014-09-02 21:27:57 -07:00
nfs4_init_deviceid_node ( & dsaddr - > id_node , server , & pdev - > dev_id ) ;
2010-10-20 00:18:04 -04:00
2011-05-31 18:48:57 -04:00
INIT_LIST_HEAD ( & dsaddrs ) ;
2010-10-20 00:18:04 -04:00
for ( i = 0 ; i < dsaddr - > ds_num ; i + + ) {
int j ;
2011-03-24 16:48:21 -04:00
u32 mp_count ;
p = xdr_inline_decode ( & stream , 4 ) ;
if ( unlikely ( ! p ) )
goto out_err_free_deviceid ;
2010-10-20 00:18:04 -04:00
2011-03-24 16:48:21 -04:00
mp_count = be32_to_cpup ( p ) ; /* multipath count */
for ( j = 0 ; j < mp_count ; j + + ) {
2014-05-29 21:06:59 +08:00
da = nfs4_decode_mp_ds_addr ( server - > nfs_client - > cl_net ,
& stream , gfp_flags ) ;
2011-05-31 18:48:57 -04:00
if ( da )
list_add_tail ( & da - > da_node , & dsaddrs ) ;
}
if ( list_empty ( & dsaddrs ) ) {
dprintk ( " %s: no suitable DS addresses found \n " ,
__func__ ) ;
goto out_err_free_deviceid ;
}
dsaddr - > ds_list [ i ] = nfs4_pnfs_ds_add ( & dsaddrs , gfp_flags ) ;
if ( ! dsaddr - > ds_list [ i ] )
goto out_err_drain_dsaddrs ;
/* If DS was already in cache, free ds addrs */
while ( ! list_empty ( & dsaddrs ) ) {
da = list_first_entry ( & dsaddrs ,
struct nfs4_pnfs_ds_addr ,
da_node ) ;
list_del_init ( & da - > da_node ) ;
kfree ( da - > da_remotestr ) ;
kfree ( da ) ;
2010-10-20 00:18:04 -04:00
}
}
2011-03-24 16:48:21 -04:00
__free_page ( scratch ) ;
2010-10-20 00:18:04 -04:00
return dsaddr ;
2011-05-31 18:48:57 -04:00
out_err_drain_dsaddrs :
while ( ! list_empty ( & dsaddrs ) ) {
da = list_first_entry ( & dsaddrs , struct nfs4_pnfs_ds_addr ,
da_node ) ;
list_del_init ( & da - > da_node ) ;
kfree ( da - > da_remotestr ) ;
kfree ( da ) ;
}
2011-03-24 16:48:21 -04:00
out_err_free_deviceid :
2010-10-20 00:18:04 -04:00
nfs4_fl_free_deviceid ( dsaddr ) ;
2011-03-24 16:48:21 -04:00
/* stripe_indicies was part of dsaddr */
goto out_err_free_scratch ;
out_err_free_stripe_indices :
kfree ( stripe_indices ) ;
out_err_free_scratch :
__free_page ( scratch ) ;
2010-10-20 00:18:04 -04:00
out_err :
dprintk ( " %s ERROR: returning NULL \n " , __func__ ) ;
return NULL ;
}
2011-03-01 01:34:21 +00:00
void
nfs4_fl_put_deviceid ( struct nfs4_file_layout_dsaddr * dsaddr )
2010-10-20 00:18:04 -04:00
{
2011-05-20 13:47:33 +02:00
nfs4_put_deviceid_node ( & dsaddr - > id_node ) ;
2010-10-20 00:18:04 -04:00
}
2011-03-01 01:34:18 +00:00
/*
* Want res = ( offset - layout - > pattern_offset ) / layout - > stripe_unit
* Then : ( ( res + fsi ) % dsaddr - > stripe_count )
*/
u32
nfs4_fl_calc_j_index ( struct pnfs_layout_segment * lseg , loff_t offset )
{
struct nfs4_filelayout_segment * flseg = FILELAYOUT_LSEG ( lseg ) ;
u64 tmp ;
tmp = offset - flseg - > pattern_offset ;
do_div ( tmp , flseg - > stripe_unit ) ;
tmp + = flseg - > first_stripe_index ;
return do_div ( tmp , flseg - > dsaddr - > stripe_count ) ;
}
u32
nfs4_fl_calc_ds_index ( struct pnfs_layout_segment * lseg , u32 j )
{
return FILELAYOUT_LSEG ( lseg ) - > dsaddr - > stripe_indices [ j ] ;
}
struct nfs_fh *
nfs4_fl_select_ds_fh ( struct pnfs_layout_segment * lseg , u32 j )
{
struct nfs4_filelayout_segment * flseg = FILELAYOUT_LSEG ( lseg ) ;
u32 i ;
if ( flseg - > stripe_type = = STRIPE_SPARSE ) {
if ( flseg - > num_fh = = 1 )
i = 0 ;
else if ( flseg - > num_fh = = 0 )
/* Use the MDS OPEN fh set in nfs_read_rpcsetup */
return NULL ;
else
i = nfs4_fl_calc_ds_index ( lseg , j ) ;
} else
i = j ;
return flseg - > fh_array [ i ] ;
}
2014-05-29 21:06:58 +08:00
/* Upon return, either ds is connected, or ds is NULL */
2011-03-01 01:34:18 +00:00
struct nfs4_pnfs_ds *
nfs4_fl_prepare_ds ( struct pnfs_layout_segment * lseg , u32 ds_idx )
{
struct nfs4_file_layout_dsaddr * dsaddr = FILELAYOUT_LSEG ( lseg ) - > dsaddr ;
struct nfs4_pnfs_ds * ds = dsaddr - > ds_list [ ds_idx ] ;
2012-04-27 17:53:42 -04:00
struct nfs4_deviceid_node * devid = FILELAYOUT_DEVID_NODE ( lseg ) ;
2013-09-26 14:08:36 -04:00
struct nfs4_pnfs_ds * ret = ds ;
2014-05-29 21:06:58 +08:00
struct nfs_server * s = NFS_SERVER ( lseg - > pls_layout - > plh_inode ) ;
2011-03-01 01:34:18 +00:00
if ( ds = = NULL ) {
2012-01-26 13:32:23 -05:00
printk ( KERN_ERR " NFS: %s: No data server for offset index %d \n " ,
2011-03-01 01:34:18 +00:00
__func__ , ds_idx ) ;
2014-12-11 15:34:59 -05:00
pnfs_generic_mark_devid_invalid ( devid ) ;
2013-09-26 14:08:36 -04:00
goto out ;
2011-03-01 01:34:18 +00:00
}
2013-09-26 14:32:56 -04:00
smp_rmb ( ) ;
2013-05-08 16:21:18 -04:00
if ( ds - > ds_clp )
2013-09-26 14:08:36 -04:00
goto out_test_devid ;
2011-03-01 01:34:18 +00:00
2014-05-29 21:06:58 +08:00
nfs4_pnfs_ds_connect ( s , ds , devid , dataserver_timeo ,
2014-05-30 18:15:58 +08:00
dataserver_retrans , 4 ,
2016-11-17 15:15:55 -05:00
s - > nfs_client - > cl_minorversion ) ;
2014-05-29 21:06:58 +08:00
2013-09-26 14:08:36 -04:00
out_test_devid :
if ( filelayout_test_devid_unavailable ( devid ) )
ret = NULL ;
out :
return ret ;
2011-03-01 01:34:18 +00:00
}
2012-04-27 17:53:45 -04:00
module_param ( dataserver_retrans , uint , 0644 ) ;
MODULE_PARM_DESC ( dataserver_retrans , " The number of times the NFSv4.1 client "
" retries a request before it attempts further "
" recovery action. " ) ;
module_param ( dataserver_timeo , uint , 0644 ) ;
MODULE_PARM_DESC ( dataserver_timeo , " The time (in tenths of a second) the "
" NFSv4.1 client waits for a response from a "
" data server before it retries an NFS request. " ) ;