2010-10-20 08:18:00 +04:00
/*
* Module for the pnfs nfs4 file layout driver .
* Defines all I / O and Policy interface operations , plus code
* to register itself with the pNFS client .
*
* Copyright ( c ) 2002
* The Regents of the University of Michigan
* All Rights Reserved
*
* Dean Hildebrand < dhildebz @ umich . edu >
*
* 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>
2011-06-20 02:33:46 +04:00
# include <linux/nfs_page.h>
2011-07-01 22:23:34 +04:00
# include <linux/module.h>
2015-05-23 00:13:32 +03:00
# include <linux/backing-dev.h>
2010-10-20 08:18:04 +04:00
2012-02-17 22:15:24 +04:00
# include <linux/sunrpc/metrics.h>
2014-05-13 01:35:52 +04:00
# include "../nfs4session.h"
# include "../internal.h"
# include "../delegation.h"
# include "filelayout.h"
# include "../nfs4trace.h"
2010-10-20 08:18:00 +04:00
# define NFSDBG_FACILITY NFSDBG_PNFS_LD
MODULE_LICENSE ( " GPL " ) ;
MODULE_AUTHOR ( " Dean Hildebrand <dhildebz@umich.edu> " ) ;
MODULE_DESCRIPTION ( " The NFSv4 file layout driver " ) ;
2011-03-01 04:34:20 +03:00
# define FILELAYOUT_POLL_RETRY_MAX (15*HZ)
2020-03-21 18:13:05 +03:00
static const struct pnfs_commit_ops filelayout_commit_ops ;
2011-03-01 04:34:20 +03:00
2011-03-01 04:34:18 +03:00
static loff_t
filelayout_get_dense_offset ( struct nfs4_filelayout_segment * flseg ,
loff_t offset )
{
u32 stripe_width = flseg - > stripe_unit * flseg - > dsaddr - > stripe_count ;
2011-08-12 00:54:28 +04:00
u64 stripe_no ;
u32 rem ;
2011-03-01 04:34:18 +03:00
offset - = flseg - > pattern_offset ;
2011-08-12 00:54:28 +04:00
stripe_no = div_u64 ( offset , stripe_width ) ;
div_u64_rem ( offset , flseg - > stripe_unit , & rem ) ;
2011-03-01 04:34:18 +03:00
2011-08-12 00:54:28 +04:00
return stripe_no * flseg - > stripe_unit + rem ;
2011-03-01 04:34:18 +03:00
}
/* This function is used by the layout driver to calculate the
* offset of the file on the dserver based on whether the
* layout type is STRIPE_DENSE or STRIPE_SPARSE
*/
static loff_t
filelayout_get_dserver_offset ( struct pnfs_layout_segment * lseg , loff_t offset )
{
struct nfs4_filelayout_segment * flseg = FILELAYOUT_LSEG ( lseg ) ;
switch ( flseg - > stripe_type ) {
case STRIPE_SPARSE :
return offset ;
case STRIPE_DENSE :
return filelayout_get_dense_offset ( flseg , offset ) ;
}
BUG ( ) ;
}
2014-06-09 19:48:35 +04:00
static void filelayout_reset_write ( struct nfs_pgio_header * hdr )
2012-04-28 01:53:46 +04:00
{
2014-06-09 19:48:35 +04:00
struct rpc_task * task = & hdr - > task ;
2012-04-28 01:53:46 +04:00
if ( ! test_and_set_bit ( NFS_IOHDR_REDO , & hdr - > flags ) ) {
dprintk ( " %s Reset task %5u for i/o through MDS "
2013-12-17 21:20:16 +04:00
" (req %s/%llu, %u bytes @ offset %llu) \n " , __func__ ,
2014-06-09 19:48:35 +04:00
hdr - > task . tk_pid ,
2012-05-22 18:10:03 +04:00
hdr - > inode - > i_sb - > s_id ,
2013-12-17 21:20:16 +04:00
( unsigned long long ) NFS_FILEID ( hdr - > inode ) ,
2014-06-09 19:48:35 +04:00
hdr - > args . count ,
( unsigned long long ) hdr - > args . offset ) ;
2012-04-28 01:53:46 +04:00
2014-06-09 19:48:38 +04:00
task - > tk_status = pnfs_write_done_resend_to_mds ( hdr ) ;
2012-04-28 01:53:46 +04:00
}
}
2014-06-09 19:48:35 +04:00
static void filelayout_reset_read ( struct nfs_pgio_header * hdr )
2012-04-28 01:53:46 +04:00
{
2014-06-09 19:48:35 +04:00
struct rpc_task * task = & hdr - > task ;
2012-04-28 01:53:46 +04:00
if ( ! test_and_set_bit ( NFS_IOHDR_REDO , & hdr - > flags ) ) {
dprintk ( " %s Reset task %5u for i/o through MDS "
2013-12-17 21:20:16 +04:00
" (req %s/%llu, %u bytes @ offset %llu) \n " , __func__ ,
2014-06-09 19:48:35 +04:00
hdr - > task . tk_pid ,
2012-05-22 18:10:03 +04:00
hdr - > inode - > i_sb - > s_id ,
2013-12-17 21:20:16 +04:00
( unsigned long long ) NFS_FILEID ( hdr - > inode ) ,
2014-06-09 19:48:35 +04:00
hdr - > args . count ,
( unsigned long long ) hdr - > args . offset ) ;
2012-04-28 01:53:46 +04:00
2014-06-09 19:48:38 +04:00
task - > tk_status = pnfs_read_done_resend_to_mds ( hdr ) ;
2012-04-28 01:53:46 +04:00
}
}
2011-03-01 04:34:20 +03:00
static int filelayout_async_handle_error ( struct rpc_task * task ,
struct nfs4_state * state ,
struct nfs_client * clp ,
2012-04-28 01:53:46 +04:00
struct pnfs_layout_segment * lseg )
2011-03-01 04:34:20 +03:00
{
2012-10-11 21:43:38 +04:00
struct pnfs_layout_hdr * lo = lseg - > pls_layout ;
struct inode * inode = lo - > plh_inode ;
2012-04-28 01:53:46 +04:00
struct nfs4_deviceid_node * devid = FILELAYOUT_DEVID_NODE ( lseg ) ;
2012-04-28 01:53:49 +04:00
struct nfs4_slot_table * tbl = & clp - > cl_session - > fc_slot_table ;
2012-03-07 19:49:41 +04:00
2011-03-01 04:34:20 +03:00
if ( task - > tk_status > = 0 )
return 0 ;
switch ( task - > tk_status ) {
2012-03-07 19:49:41 +04:00
/* DS session errors */
2011-03-01 04:34:20 +03:00
case - NFS4ERR_BADSESSION :
case - NFS4ERR_BADSLOT :
case - NFS4ERR_BAD_HIGH_SLOT :
case - NFS4ERR_DEADSESSION :
case - NFS4ERR_CONN_NOT_BOUND_TO_SESSION :
case - NFS4ERR_SEQ_FALSE_RETRY :
case - NFS4ERR_SEQ_MISORDERED :
dprintk ( " %s ERROR %d, Reset session. Exchangeid "
" flags 0x%x \n " , __func__ , task - > tk_status ,
clp - > cl_exchange_flags ) ;
2012-05-27 21:02:53 +04:00
nfs4_schedule_session_recovery ( clp - > cl_session , task - > tk_status ) ;
2011-03-01 04:34:20 +03:00
break ;
case - NFS4ERR_DELAY :
case - NFS4ERR_GRACE :
rpc_delay ( task , FILELAYOUT_POLL_RETRY_MAX ) ;
break ;
2011-05-03 21:43:03 +04:00
case - NFS4ERR_RETRY_UNCACHED_REP :
break ;
2012-04-28 01:53:53 +04:00
/* Invalidate Layout errors */
2017-06-23 17:26:58 +03:00
case - NFS4ERR_ACCESS :
2012-04-28 01:53:53 +04:00
case - NFS4ERR_PNFS_NO_LAYOUT :
case - ESTALE : /* mapped NFS4ERR_STALE */
case - EBADHANDLE : /* mapped NFS4ERR_BADHANDLE */
case - EISDIR : /* mapped NFS4ERR_ISDIR */
case - NFS4ERR_FHEXPIRED :
case - NFS4ERR_WRONG_TYPE :
dprintk ( " %s Invalid layout error %d \n " , __func__ ,
task - > tk_status ) ;
/*
* Destroy layout so new i / o will get a new layout .
* Layout will not be destroyed until all current lseg
* references are put . Mark layout as invalid to resend failed
* i / o and all i / o waiting on the slot table to the MDS until
* layout is destroyed and a new valid layout is obtained .
*/
2012-05-22 16:09:28 +04:00
pnfs_destroy_layout ( NFS_I ( inode ) ) ;
2012-04-28 01:53:53 +04:00
rpc_wake_up ( & tbl - > slot_tbl_waitq ) ;
goto reset ;
2012-04-28 01:53:46 +04:00
/* RPC connection errors */
case - ECONNREFUSED :
case - EHOSTDOWN :
case - EHOSTUNREACH :
case - ENETUNREACH :
case - EIO :
case - ETIMEDOUT :
case - EPIPE :
2022-05-19 00:08:58 +03:00
case - EPROTO :
case - ENODEV :
2012-04-28 01:53:46 +04:00
dprintk ( " %s DS connection error %d \n " , __func__ ,
task - > tk_status ) ;
2012-09-19 03:51:12 +04:00
nfs4_mark_deviceid_unavailable ( devid ) ;
2014-09-05 20:53:29 +04:00
pnfs_error_mark_layout_for_return ( inode , lseg ) ;
2017-06-23 17:26:58 +03:00
pnfs_set_lo_fail ( lseg ) ;
2012-04-28 01:53:49 +04:00
rpc_wake_up ( & tbl - > slot_tbl_waitq ) ;
2020-08-24 01:36:59 +03:00
fallthrough ;
2011-03-01 04:34:20 +03:00
default :
2012-04-28 01:53:53 +04:00
reset :
2012-04-28 01:53:46 +04:00
dprintk ( " %s Retry through MDS. Error %d \n " , __func__ ,
2011-03-01 04:34:20 +03:00
task - > tk_status ) ;
2012-04-28 01:53:46 +04:00
return - NFS4ERR_RESET_TO_MDS ;
2011-03-01 04:34:20 +03:00
}
task - > tk_status = 0 ;
return - EAGAIN ;
}
/* NFS_PROTO call done callback routines */
static int filelayout_read_done_cb ( struct rpc_task * task ,
2014-06-09 19:48:35 +04:00
struct nfs_pgio_header * hdr )
2011-03-01 04:34:20 +03:00
{
2012-04-28 01:53:46 +04:00
int err ;
2011-03-01 04:34:20 +03:00
2014-06-09 19:48:35 +04:00
trace_nfs4_pnfs_read ( hdr , task - > tk_status ) ;
err = filelayout_async_handle_error ( task , hdr - > args . context - > state ,
hdr - > ds_clp , hdr - > lseg ) ;
2011-03-01 04:34:20 +03:00
2012-04-28 01:53:46 +04:00
switch ( err ) {
case - NFS4ERR_RESET_TO_MDS :
2014-06-09 19:48:35 +04:00
filelayout_reset_read ( hdr ) ;
2012-04-28 01:53:46 +04:00
return task - > tk_status ;
case - EAGAIN :
2011-10-19 23:17:29 +04:00
rpc_restart_call_prepare ( task ) ;
2011-03-01 04:34:20 +03:00
return - EAGAIN ;
}
return 0 ;
}
2011-03-23 16:27:54 +03:00
/*
* We reference the rpc_cred of the first WRITE that triggers the need for
* a LAYOUTCOMMIT , and use it to send the layoutcommit compound .
* rfc5661 is not clear about which credential should be used .
*/
static void
2014-06-09 19:48:35 +04:00
filelayout_set_layoutcommit ( struct nfs_pgio_header * hdr )
2011-03-23 16:27:54 +03:00
{
2016-06-27 01:54:58 +03:00
loff_t end_offs = 0 ;
2012-04-20 22:47:44 +04:00
if ( FILELAYOUT_LSEG ( hdr - > lseg ) - > commit_through_mds | |
2016-06-27 01:54:58 +03:00
hdr - > res . verf - > committed = = NFS_FILE_SYNC )
2011-03-23 16:27:54 +03:00
return ;
2016-06-27 01:54:58 +03:00
if ( hdr - > res . verf - > committed = = NFS_DATA_SYNC )
end_offs = hdr - > mds_offset + ( loff_t ) hdr - > res . count ;
2011-03-23 16:27:54 +03:00
2016-06-27 01:54:58 +03:00
/* Note: if the write is unstable, don't set end_offs until commit */
pnfs_set_layoutcommit ( hdr - > inode , hdr - > lseg , end_offs ) ;
2014-06-05 02:54:57 +04:00
dprintk ( " %s inode %lu pls_end_pos %lu \n " , __func__ , hdr - > inode - > i_ino ,
2012-04-20 22:47:44 +04:00
( unsigned long ) NFS_I ( hdr - > inode ) - > layout - > plh_lwb ) ;
2011-03-23 16:27:54 +03:00
}
2012-09-19 03:51:12 +04:00
bool
filelayout_test_devid_unavailable ( struct nfs4_deviceid_node * node )
{
return filelayout_test_devid_invalid ( node ) | |
nfs4_test_deviceid_unavailable ( node ) ;
}
static bool
filelayout_reset_to_mds ( struct pnfs_layout_segment * lseg )
{
struct nfs4_deviceid_node * node = FILELAYOUT_DEVID_NODE ( lseg ) ;
2012-09-21 22:48:04 +04:00
return filelayout_test_devid_unavailable ( node ) ;
2012-09-19 03:51:12 +04:00
}
2011-03-01 04:34:19 +03:00
/*
* Call ops for the async read / write cases
* In the case of dense layouts , the offset needs to be reset to its
* original value .
*/
static void filelayout_read_prepare ( struct rpc_task * task , void * data )
{
2014-06-09 19:48:35 +04:00
struct nfs_pgio_header * hdr = data ;
2011-03-01 04:34:19 +03:00
2014-06-09 19:48:35 +04:00
if ( unlikely ( test_bit ( NFS_CONTEXT_BAD , & hdr - > args . context - > flags ) ) ) {
2013-03-19 03:45:14 +04:00
rpc_exit ( task , - EIO ) ;
return ;
}
2014-06-09 19:48:35 +04:00
if ( filelayout_reset_to_mds ( hdr - > lseg ) ) {
2012-04-28 01:53:48 +04:00
dprintk ( " %s task %u reset io to MDS \n " , __func__ , task - > tk_pid ) ;
2014-06-09 19:48:35 +04:00
filelayout_reset_read ( hdr ) ;
2012-04-28 01:53:48 +04:00
rpc_exit ( task , 0 ) ;
return ;
}
2014-06-09 19:48:35 +04:00
hdr - > pgio_done_cb = filelayout_read_done_cb ;
2011-03-01 04:34:20 +03:00
2017-01-10 00:51:52 +03:00
if ( nfs4_setup_sequence ( hdr - > ds_clp ,
2014-06-09 19:48:35 +04:00
& hdr - > args . seq_args ,
& hdr - > res . seq_res ,
2013-03-17 23:52:00 +04:00
task ) )
return ;
2014-06-09 19:48:35 +04:00
if ( nfs4_set_rw_stateid ( & hdr - > args . stateid , hdr - > args . context ,
hdr - > args . lock_context , FMODE_READ ) = = - EIO )
2014-03-04 21:31:09 +04:00
rpc_exit ( task , - EIO ) ; /* lost lock, terminate I/O */
2011-03-01 04:34:19 +03:00
}
static void filelayout_read_call_done ( struct rpc_task * task , void * data )
{
2014-06-09 19:48:35 +04:00
struct nfs_pgio_header * hdr = data ;
2011-03-01 04:34:19 +03:00
2014-06-09 19:48:35 +04:00
if ( test_bit ( NFS_IOHDR_REDO , & hdr - > flags ) & &
2014-01-29 20:34:38 +04:00
task - > tk_status = = 0 ) {
2014-06-09 19:48:35 +04:00
nfs41_sequence_done ( task , & hdr - > res . seq_res ) ;
2012-04-28 01:53:48 +04:00
return ;
2014-01-29 20:34:38 +04:00
}
2012-04-28 01:53:48 +04:00
2011-03-01 04:34:19 +03:00
/* Note this may cause RPC to be resent */
2014-06-09 19:48:35 +04:00
hdr - > mds_ops - > rpc_call_done ( task , data ) ;
2011-03-01 04:34:19 +03:00
}
2012-02-17 22:15:24 +04:00
static void filelayout_read_count_stats ( struct rpc_task * task , void * data )
{
2014-06-09 19:48:35 +04:00
struct nfs_pgio_header * hdr = data ;
2012-02-17 22:15:24 +04:00
2014-06-09 19:48:35 +04:00
rpc_count_iostats ( task , NFS_SERVER ( hdr - > inode ) - > client - > cl_metrics ) ;
2012-02-17 22:15:24 +04:00
}
2011-03-03 18:13:47 +03:00
static int filelayout_write_done_cb ( struct rpc_task * task ,
2014-06-09 19:48:35 +04:00
struct nfs_pgio_header * hdr )
2011-03-03 18:13:47 +03:00
{
2012-04-28 01:53:46 +04:00
int err ;
2014-06-09 19:48:35 +04:00
trace_nfs4_pnfs_write ( hdr , task - > tk_status ) ;
err = filelayout_async_handle_error ( task , hdr - > args . context - > state ,
hdr - > ds_clp , hdr - > lseg ) ;
2012-04-28 01:53:46 +04:00
switch ( err ) {
case - NFS4ERR_RESET_TO_MDS :
2014-06-09 19:48:35 +04:00
filelayout_reset_write ( hdr ) ;
2012-04-28 01:53:46 +04:00
return task - > tk_status ;
case - EAGAIN :
2011-10-19 23:17:29 +04:00
rpc_restart_call_prepare ( task ) ;
2011-03-03 18:13:47 +03:00
return - EAGAIN ;
}
2014-06-09 19:48:35 +04:00
filelayout_set_layoutcommit ( hdr ) ;
2016-07-21 16:43:43 +03:00
/* zero out the fattr */
hdr - > fattr . valid = 0 ;
if ( task - > tk_status > = 0 )
nfs_writeback_update_inode ( hdr ) ;
2011-03-03 18:13:47 +03:00
return 0 ;
}
2011-03-23 16:27:53 +03:00
static int filelayout_commit_done_cb ( struct rpc_task * task ,
2012-04-20 22:47:39 +04:00
struct nfs_commit_data * data )
2011-03-23 16:27:53 +03:00
{
2012-04-28 01:53:46 +04:00
int err ;
2013-08-14 23:31:28 +04:00
trace_nfs4_pnfs_commit_ds ( data , task - > tk_status ) ;
2012-04-28 01:53:46 +04:00
err = filelayout_async_handle_error ( task , NULL , data - > ds_clp ,
data - > lseg ) ;
switch ( err ) {
case - NFS4ERR_RESET_TO_MDS :
2014-12-11 23:34:59 +03:00
pnfs_generic_prepare_to_resend_writes ( data ) ;
2012-04-28 01:53:46 +04:00
return - EAGAIN ;
case - EAGAIN :
rpc_restart_call_prepare ( task ) ;
2011-03-23 16:27:53 +03:00
return - EAGAIN ;
}
2016-06-26 19:27:25 +03:00
pnfs_set_layoutcommit ( data - > inode , data - > lseg , data - > lwb ) ;
2014-08-07 06:15:03 +04:00
2011-03-23 16:27:53 +03:00
return 0 ;
}
2011-03-03 18:13:47 +03:00
static void filelayout_write_prepare ( struct rpc_task * task , void * data )
{
2014-06-09 19:48:35 +04:00
struct nfs_pgio_header * hdr = data ;
2011-03-03 18:13:47 +03:00
2014-06-09 19:48:35 +04:00
if ( unlikely ( test_bit ( NFS_CONTEXT_BAD , & hdr - > args . context - > flags ) ) ) {
2013-03-19 03:45:14 +04:00
rpc_exit ( task , - EIO ) ;
return ;
}
2014-06-09 19:48:35 +04:00
if ( filelayout_reset_to_mds ( hdr - > lseg ) ) {
2012-04-28 01:53:48 +04:00
dprintk ( " %s task %u reset io to MDS \n " , __func__ , task - > tk_pid ) ;
2014-06-09 19:48:35 +04:00
filelayout_reset_write ( hdr ) ;
2012-04-28 01:53:48 +04:00
rpc_exit ( task , 0 ) ;
return ;
}
2017-01-10 00:51:52 +03:00
if ( nfs4_setup_sequence ( hdr - > ds_clp ,
2014-06-09 19:48:35 +04:00
& hdr - > args . seq_args ,
& hdr - > res . seq_res ,
2013-03-17 23:52:00 +04:00
task ) )
return ;
2014-06-09 19:48:35 +04:00
if ( nfs4_set_rw_stateid ( & hdr - > args . stateid , hdr - > args . context ,
hdr - > args . lock_context , FMODE_WRITE ) = = - EIO )
2014-03-04 21:31:09 +04:00
rpc_exit ( task , - EIO ) ; /* lost lock, terminate I/O */
2011-03-03 18:13:47 +03:00
}
static void filelayout_write_call_done ( struct rpc_task * task , void * data )
{
2014-06-09 19:48:35 +04:00
struct nfs_pgio_header * hdr = data ;
2011-03-03 18:13:47 +03:00
2014-06-09 19:48:35 +04:00
if ( test_bit ( NFS_IOHDR_REDO , & hdr - > flags ) & &
2014-01-29 20:34:38 +04:00
task - > tk_status = = 0 ) {
2014-06-09 19:48:35 +04:00
nfs41_sequence_done ( task , & hdr - > res . seq_res ) ;
2012-04-28 01:53:48 +04:00
return ;
2014-01-29 20:34:38 +04:00
}
2012-04-28 01:53:48 +04:00
2011-03-03 18:13:47 +03:00
/* Note this may cause RPC to be resent */
2014-06-09 19:48:35 +04:00
hdr - > mds_ops - > rpc_call_done ( task , data ) ;
2011-03-03 18:13:47 +03:00
}
2012-02-17 22:15:24 +04:00
static void filelayout_write_count_stats ( struct rpc_task * task , void * data )
{
2014-06-09 19:48:35 +04:00
struct nfs_pgio_header * hdr = data ;
2012-02-17 22:15:24 +04:00
2014-06-09 19:48:35 +04:00
rpc_count_iostats ( task , NFS_SERVER ( hdr - > inode ) - > client - > cl_metrics ) ;
2012-02-17 22:15:24 +04:00
}
2012-04-20 22:47:39 +04:00
static void filelayout_commit_prepare ( struct rpc_task * task , void * data )
2011-03-23 16:27:53 +03:00
{
2012-04-20 22:47:39 +04:00
struct nfs_commit_data * wdata = data ;
2011-03-23 16:27:53 +03:00
2017-01-10 00:51:52 +03:00
nfs4_setup_sequence ( wdata - > ds_clp ,
2012-10-23 04:28:44 +04:00
& wdata - > args . seq_args ,
& wdata - > res . seq_res ,
task ) ;
2012-04-20 22:47:39 +04:00
}
static void filelayout_commit_count_stats ( struct rpc_task * task , void * data )
{
struct nfs_commit_data * cdata = data ;
rpc_count_iostats ( task , NFS_SERVER ( cdata - > inode ) - > client - > cl_metrics ) ;
}
2012-03-11 21:11:00 +04:00
static const struct rpc_call_ops filelayout_read_call_ops = {
2011-03-01 04:34:19 +03:00
. rpc_call_prepare = filelayout_read_prepare ,
. rpc_call_done = filelayout_read_call_done ,
2012-02-17 22:15:24 +04:00
. rpc_count_stats = filelayout_read_count_stats ,
2014-12-11 23:34:59 +03:00
. rpc_release = pnfs_generic_rw_release ,
2011-03-01 04:34:19 +03:00
} ;
2012-03-11 21:11:00 +04:00
static const struct rpc_call_ops filelayout_write_call_ops = {
2011-03-03 18:13:47 +03:00
. rpc_call_prepare = filelayout_write_prepare ,
. rpc_call_done = filelayout_write_call_done ,
2012-02-17 22:15:24 +04:00
. rpc_count_stats = filelayout_write_count_stats ,
2014-12-11 23:34:59 +03:00
. rpc_release = pnfs_generic_rw_release ,
2011-03-03 18:13:47 +03:00
} ;
2012-03-11 21:11:00 +04:00
static const struct rpc_call_ops filelayout_commit_call_ops = {
2012-04-20 22:47:39 +04:00
. rpc_call_prepare = filelayout_commit_prepare ,
2014-12-11 23:34:59 +03:00
. rpc_call_done = pnfs_generic_write_commit_done ,
2012-04-20 22:47:39 +04:00
. rpc_count_stats = filelayout_commit_count_stats ,
2014-12-11 23:34:59 +03:00
. rpc_release = pnfs_generic_commit_release ,
2011-03-23 16:27:53 +03:00
} ;
2011-03-01 04:34:19 +03:00
static enum pnfs_try_status
2014-06-09 19:48:35 +04:00
filelayout_read_pagelist ( struct nfs_pgio_header * hdr )
2011-03-01 04:34:19 +03:00
{
2012-04-20 22:47:44 +04:00
struct pnfs_layout_segment * lseg = hdr - > lseg ;
2011-03-01 04:34:19 +03:00
struct nfs4_pnfs_ds * ds ;
2013-09-06 22:14:00 +04:00
struct rpc_clnt * ds_clnt ;
2014-06-09 19:48:35 +04:00
loff_t offset = hdr - > args . offset ;
2011-03-01 04:34:19 +03:00
u32 j , idx ;
struct nfs_fh * fh ;
2017-02-28 01:30:02 +03:00
dprintk ( " --> %s ino %lu pgbase %u req %zu@%llu \n " ,
2012-04-20 22:47:44 +04:00
__func__ , hdr - > inode - > i_ino ,
2014-06-09 19:48:35 +04:00
hdr - > args . pgbase , ( size_t ) hdr - > args . count , offset ) ;
2011-03-01 04:34:19 +03:00
/* Retrieve the correct rpc_client for the byte range */
j = nfs4_fl_calc_j_index ( lseg , offset ) ;
idx = nfs4_fl_calc_ds_index ( lseg , j ) ;
ds = nfs4_fl_prepare_ds ( lseg , idx ) ;
2012-04-28 01:53:43 +04:00
if ( ! ds )
2011-03-01 04:34:19 +03:00
return PNFS_NOT_ATTEMPTED ;
2013-09-06 22:14:00 +04:00
ds_clnt = nfs4_find_or_create_ds_client ( ds - > ds_clp , hdr - > inode ) ;
if ( IS_ERR ( ds_clnt ) )
return PNFS_NOT_ATTEMPTED ;
2012-04-28 01:53:51 +04:00
dprintk ( " %s USE DS: %s cl_count %d \n " , __func__ ,
2017-10-20 12:53:38 +03:00
ds - > ds_remotestr , refcount_read ( & ds - > ds_clp - > cl_count ) ) ;
2011-03-01 04:34:19 +03:00
/* No multipath support. Use first DS */
2017-10-20 12:53:38 +03:00
refcount_inc ( & ds - > ds_clp - > cl_count ) ;
2014-06-09 19:48:35 +04:00
hdr - > ds_clp = ds - > ds_clp ;
2014-09-17 01:35:51 +04:00
hdr - > ds_commit_idx = idx ;
2011-03-01 04:34:19 +03:00
fh = nfs4_fl_select_ds_fh ( lseg , j ) ;
if ( fh )
2014-06-09 19:48:35 +04:00
hdr - > args . fh = fh ;
2011-03-01 04:34:19 +03:00
2014-06-09 19:48:35 +04:00
hdr - > args . offset = filelayout_get_dserver_offset ( lseg , offset ) ;
hdr - > mds_offset = offset ;
2011-03-01 04:34:19 +03:00
/* Perform an asynchronous read to ds */
2014-06-13 19:02:25 +04:00
nfs_initiate_pgio ( ds_clnt , hdr , hdr - > cred ,
NFS_PROTO ( hdr - > inode ) , & filelayout_read_call_ops ,
0 , RPC_TASK_SOFTCONN ) ;
2011-03-01 04:34:19 +03:00
return PNFS_ATTEMPTED ;
}
2011-03-03 18:13:47 +03:00
/* Perform async writes. */
2011-03-03 18:13:45 +03:00
static enum pnfs_try_status
2014-06-09 19:48:35 +04:00
filelayout_write_pagelist ( struct nfs_pgio_header * hdr , int sync )
2011-03-03 18:13:45 +03:00
{
2012-04-20 22:47:44 +04:00
struct pnfs_layout_segment * lseg = hdr - > lseg ;
2011-03-03 18:13:47 +03:00
struct nfs4_pnfs_ds * ds ;
2013-09-06 22:14:00 +04:00
struct rpc_clnt * ds_clnt ;
2014-06-09 19:48:35 +04:00
loff_t offset = hdr - > args . offset ;
2011-03-03 18:13:47 +03:00
u32 j , idx ;
struct nfs_fh * fh ;
/* Retrieve the correct rpc_client for the byte range */
j = nfs4_fl_calc_j_index ( lseg , offset ) ;
idx = nfs4_fl_calc_ds_index ( lseg , j ) ;
ds = nfs4_fl_prepare_ds ( lseg , idx ) ;
2012-04-28 01:53:43 +04:00
if ( ! ds )
2011-03-03 18:13:47 +03:00
return PNFS_NOT_ATTEMPTED ;
2013-09-06 22:14:00 +04:00
ds_clnt = nfs4_find_or_create_ds_client ( ds - > ds_clp , hdr - > inode ) ;
if ( IS_ERR ( ds_clnt ) )
return PNFS_NOT_ATTEMPTED ;
2017-02-28 01:30:02 +03:00
dprintk ( " %s ino %lu sync %d req %zu@%llu DS: %s cl_count %d \n " ,
2014-06-09 19:48:35 +04:00
__func__ , hdr - > inode - > i_ino , sync , ( size_t ) hdr - > args . count ,
2017-10-20 12:53:38 +03:00
offset , ds - > ds_remotestr , refcount_read ( & ds - > ds_clp - > cl_count ) ) ;
2011-03-03 18:13:47 +03:00
2014-06-09 19:48:35 +04:00
hdr - > pgio_done_cb = filelayout_write_done_cb ;
2017-10-20 12:53:38 +03:00
refcount_inc ( & ds - > ds_clp - > cl_count ) ;
2014-06-09 19:48:35 +04:00
hdr - > ds_clp = ds - > ds_clp ;
2014-09-17 01:35:51 +04:00
hdr - > ds_commit_idx = idx ;
2011-03-03 18:13:47 +03:00
fh = nfs4_fl_select_ds_fh ( lseg , j ) ;
if ( fh )
2014-06-09 19:48:35 +04:00
hdr - > args . fh = fh ;
hdr - > args . offset = filelayout_get_dserver_offset ( lseg , offset ) ;
2011-03-03 18:13:47 +03:00
/* Perform an asynchronous write */
2014-06-13 19:02:25 +04:00
nfs_initiate_pgio ( ds_clnt , hdr , hdr - > cred ,
NFS_PROTO ( hdr - > inode ) , & filelayout_write_call_ops ,
sync , RPC_TASK_SOFTCONN ) ;
2011-03-03 18:13:47 +03:00
return PNFS_ATTEMPTED ;
2011-03-03 18:13:45 +03:00
}
2017-03-21 01:07:02 +03:00
static int
filelayout_check_deviceid ( struct pnfs_layout_hdr * lo ,
struct nfs4_filelayout_segment * fl ,
gfp_t gfp_flags )
{
struct nfs4_deviceid_node * d ;
struct nfs4_file_layout_dsaddr * dsaddr ;
int status = - EINVAL ;
2017-07-21 00:00:02 +03:00
/* Is the deviceid already set? If so, we're good. */
if ( fl - > dsaddr ! = NULL )
return 0 ;
2017-03-21 01:07:02 +03:00
/* find and reference the deviceid */
d = nfs4_find_get_deviceid ( NFS_SERVER ( lo - > plh_inode ) , & fl - > deviceid ,
lo - > plh_lc_cred , gfp_flags ) ;
if ( d = = NULL )
goto out ;
dsaddr = container_of ( d , struct nfs4_file_layout_dsaddr , id_node ) ;
/* Found deviceid is unavailable */
if ( filelayout_test_devid_unavailable ( & dsaddr - > id_node ) )
goto out_put ;
if ( fl - > first_stripe_index > = dsaddr - > stripe_count ) {
dprintk ( " %s Bad first_stripe_index %u \n " ,
__func__ , fl - > first_stripe_index ) ;
goto out_put ;
}
if ( ( fl - > stripe_type = = STRIPE_SPARSE & &
fl - > num_fh > 1 & & fl - > num_fh ! = dsaddr - > ds_num ) | |
( fl - > stripe_type = = STRIPE_DENSE & &
fl - > num_fh ! = dsaddr - > stripe_count ) ) {
dprintk ( " %s num_fh %u not valid for given packing \n " ,
__func__ , fl - > num_fh ) ;
goto out_put ;
}
status = 0 ;
2017-07-21 00:00:02 +03:00
/*
* Atomic compare and xchange to ensure we don ' t scribble
* over a non - NULL pointer .
*/
if ( cmpxchg ( & fl - > dsaddr , NULL , dsaddr ) ! = NULL )
goto out_put ;
2017-03-21 01:07:02 +03:00
out :
return status ;
out_put :
nfs4_fl_put_deviceid ( dsaddr ) ;
goto out ;
}
2010-10-20 08:18:04 +04:00
/*
* filelayout_check_layout ( )
*
* Make sure layout segment parameters are sane WRT the device .
* At this point no generic layer initialization of the lseg has occurred ,
* and nothing has been added to the layout_hdr cache .
*
*/
static int
filelayout_check_layout ( struct pnfs_layout_hdr * lo ,
struct nfs4_filelayout_segment * fl ,
struct nfs4_layoutget_res * lgr ,
2011-05-12 02:00:51 +04:00
gfp_t gfp_flags )
2010-10-20 08:18:04 +04:00
{
int status = - EINVAL ;
dprintk ( " --> %s \n " , __func__ ) ;
2011-06-14 02:22:38 +04:00
/* FIXME: remove this check when layout segment support is added */
if ( lgr - > range . offset ! = 0 | |
lgr - > range . length ! = NFS4_MAX_UINT64 ) {
dprintk ( " %s Only whole file layouts supported. Use MDS i/o \n " ,
__func__ ) ;
goto out ;
}
2010-10-20 08:18:04 +04:00
if ( fl - > pattern_offset > lgr - > range . offset ) {
2011-02-23 03:31:57 +03:00
dprintk ( " %s pattern_offset %lld too large \n " ,
2010-10-20 08:18:04 +04:00
__func__ , fl - > pattern_offset ) ;
goto out ;
}
2014-05-15 19:56:56 +04:00
if ( ! fl - > stripe_unit ) {
2011-02-23 02:56:01 +03:00
dprintk ( " %s Invalid stripe unit (%u) \n " ,
2010-10-20 08:18:04 +04:00
__func__ , fl - > stripe_unit ) ;
goto out ;
}
status = 0 ;
out :
dprintk ( " --> %s returns %d \n " , __func__ , status ) ;
return status ;
}
2015-09-14 15:12:21 +03:00
static void _filelayout_free_lseg ( struct nfs4_filelayout_segment * fl )
2010-10-20 08:18:04 +04:00
{
int i ;
2015-09-14 15:12:21 +03:00
if ( fl - > fh_array ) {
for ( i = 0 ; i < fl - > num_fh ; i + + ) {
if ( ! fl - > fh_array [ i ] )
break ;
kfree ( fl - > fh_array [ i ] ) ;
}
kfree ( fl - > fh_array ) ;
2010-10-20 08:18:04 +04:00
}
kfree ( fl ) ;
}
static int
filelayout_decode_layout ( struct pnfs_layout_hdr * flo ,
struct nfs4_filelayout_segment * fl ,
struct nfs4_layoutget_res * lgr ,
2011-05-12 02:00:51 +04:00
gfp_t gfp_flags )
2010-10-20 08:18:04 +04:00
{
2011-03-24 23:48:21 +03:00
struct xdr_stream stream ;
2011-05-19 22:16:47 +04:00
struct xdr_buf buf ;
2011-03-24 23:48:21 +03:00
struct page * scratch ;
__be32 * p ;
2010-10-20 08:18:04 +04:00
uint32_t nfl_util ;
int i ;
dprintk ( " %s: set_layout_map Begin \n " , __func__ ) ;
2011-05-12 02:00:51 +04:00
scratch = alloc_page ( gfp_flags ) ;
2011-03-24 23:48:21 +03:00
if ( ! scratch )
return - ENOMEM ;
2011-05-19 22:16:47 +04:00
xdr_init_decode_pages ( & stream , & buf , lgr - > layoutp - > pages , lgr - > layoutp - > len ) ;
2020-11-11 23:52:47 +03:00
xdr_set_scratch_page ( & stream , scratch ) ;
2011-03-24 23:48:21 +03:00
/* 20 = ufl_util (4), first_stripe_index (4), pattern_offset (8),
* num_fh ( 4 ) */
p = xdr_inline_decode ( & stream , NFS4_DEVICEID4_SIZE + 20 ) ;
if ( unlikely ( ! p ) )
goto out_err ;
2017-03-21 01:07:01 +03:00
memcpy ( & fl - > deviceid , p , sizeof ( fl - > deviceid ) ) ;
2010-10-20 08:18:04 +04:00
p + = XDR_QUADLEN ( NFS4_DEVICEID4_SIZE ) ;
2017-03-21 01:07:01 +03:00
nfs4_print_deviceid ( & fl - > deviceid ) ;
2010-10-20 08:18:04 +04:00
nfl_util = be32_to_cpup ( p + + ) ;
if ( nfl_util & NFL4_UFLG_COMMIT_THRU_MDS )
fl - > commit_through_mds = 1 ;
if ( nfl_util & NFL4_UFLG_DENSE )
fl - > stripe_type = STRIPE_DENSE ;
else
fl - > stripe_type = STRIPE_SPARSE ;
fl - > stripe_unit = nfl_util & ~ NFL4_UFLG_MASK ;
fl - > first_stripe_index = be32_to_cpup ( p + + ) ;
p = xdr_decode_hyper ( p , & fl - > pattern_offset ) ;
fl - > num_fh = be32_to_cpup ( p + + ) ;
dprintk ( " %s: nfl_util 0x%X num_fh %u fsi %u po %llu \n " ,
__func__ , nfl_util , fl - > num_fh , fl - > first_stripe_index ,
fl - > pattern_offset ) ;
2011-06-14 02:36:17 +04:00
/* Note that a zero value for num_fh is legal for STRIPE_SPARSE.
* Futher checking is done in filelayout_check_layout */
2011-10-25 20:18:03 +04:00
if ( fl - > num_fh >
2011-06-14 02:36:17 +04:00
max ( NFS4_PNFS_MAX_STRIPE_CNT , NFS4_PNFS_MAX_MULTI_CNT ) )
2011-03-24 23:48:21 +03:00
goto out_err ;
2011-06-14 02:36:17 +04:00
if ( fl - > num_fh > 0 ) {
2012-10-11 22:36:52 +04:00
fl - > fh_array = kcalloc ( fl - > num_fh , sizeof ( fl - > fh_array [ 0 ] ) ,
2011-06-14 02:36:17 +04:00
gfp_flags ) ;
if ( ! fl - > fh_array )
goto out_err ;
}
2010-10-20 08:18:04 +04:00
for ( i = 0 ; i < fl - > num_fh ; i + + ) {
/* Do we want to use a mempool here? */
2011-05-12 02:00:51 +04:00
fl - > fh_array [ i ] = kmalloc ( sizeof ( struct nfs_fh ) , gfp_flags ) ;
2011-03-24 23:48:21 +03:00
if ( ! fl - > fh_array [ i ] )
2015-09-14 15:12:21 +03:00
goto out_err ;
2011-03-24 23:48:21 +03:00
p = xdr_inline_decode ( & stream , 4 ) ;
if ( unlikely ( ! p ) )
2015-09-14 15:12:21 +03:00
goto out_err ;
2010-10-20 08:18:04 +04:00
fl - > fh_array [ i ] - > size = be32_to_cpup ( p + + ) ;
2021-05-11 11:49:42 +03:00
if ( fl - > fh_array [ i ] - > size > NFS_MAXFHSIZE ) {
2012-01-26 22:32:22 +04:00
printk ( KERN_ERR " NFS: Too big fh %d received %d \n " ,
2010-10-20 08:18:04 +04:00
i , fl - > fh_array [ i ] - > size ) ;
2015-09-14 15:12:21 +03:00
goto out_err ;
2010-10-20 08:18:04 +04:00
}
2011-03-24 23:48:21 +03:00
p = xdr_inline_decode ( & stream , fl - > fh_array [ i ] - > size ) ;
if ( unlikely ( ! p ) )
2015-09-14 15:12:21 +03:00
goto out_err ;
2010-10-20 08:18:04 +04:00
memcpy ( fl - > fh_array [ i ] - > data , p , fl - > fh_array [ i ] - > size ) ;
dprintk ( " DEBUG: %s: fh len %d \n " , __func__ ,
fl - > fh_array [ i ] - > size ) ;
}
2011-03-24 23:48:21 +03:00
__free_page ( scratch ) ;
2010-10-20 08:18:04 +04:00
return 0 ;
2011-03-24 23:48:21 +03:00
out_err :
__free_page ( scratch ) ;
return - EIO ;
2010-10-20 08:18:04 +04:00
}
2011-03-23 16:27:49 +03:00
static void
filelayout_free_lseg ( struct pnfs_layout_segment * lseg )
{
struct nfs4_filelayout_segment * fl = FILELAYOUT_LSEG ( lseg ) ;
dprintk ( " --> %s \n " , __func__ ) ;
2017-09-29 16:36:43 +03:00
if ( fl - > dsaddr ! = NULL )
nfs4_fl_put_deviceid ( fl - > dsaddr ) ;
2012-04-20 22:47:38 +04:00
/* This assumes a single RW lseg */
if ( lseg - > pls_range . iomode = = IOMODE_RW ) {
struct nfs4_filelayout * flo ;
2020-03-20 23:04:06 +03:00
struct inode * inode ;
2012-04-20 22:47:38 +04:00
flo = FILELAYOUT_FROM_HDR ( lseg - > pls_layout ) ;
2020-03-20 23:04:06 +03:00
inode = flo - > generic_hdr . plh_inode ;
spin_lock ( & inode - > i_lock ) ;
pnfs_generic_ds_cinfo_release_lseg ( & flo - > commit_info , lseg ) ;
spin_unlock ( & inode - > i_lock ) ;
2012-04-20 22:47:38 +04:00
}
2011-03-23 16:27:49 +03:00
_filelayout_free_lseg ( fl ) ;
}
2010-10-20 08:18:04 +04:00
static struct pnfs_layout_segment *
filelayout_alloc_lseg ( struct pnfs_layout_hdr * layoutid ,
2011-05-12 02:00:51 +04:00
struct nfs4_layoutget_res * lgr ,
gfp_t gfp_flags )
2010-10-20 08:18:04 +04:00
{
struct nfs4_filelayout_segment * fl ;
int rc ;
dprintk ( " --> %s \n " , __func__ ) ;
2011-05-12 02:00:51 +04:00
fl = kzalloc ( sizeof ( * fl ) , gfp_flags ) ;
2010-10-20 08:18:04 +04:00
if ( ! fl )
return NULL ;
2017-03-21 01:07:01 +03:00
rc = filelayout_decode_layout ( layoutid , fl , lgr , gfp_flags ) ;
if ( rc ! = 0 | | filelayout_check_layout ( layoutid , fl , lgr , gfp_flags ) ) {
2010-10-20 08:18:04 +04:00
_filelayout_free_lseg ( fl ) ;
return NULL ;
}
return & fl - > generic_hdr ;
}
2011-03-01 04:34:14 +03:00
/*
* filelayout_pg_test ( ) . Called by nfs_can_coalesce_requests ( )
*
2014-05-15 19:56:43 +04:00
* Return 0 if @ req cannot be coalesced into @ pgio , otherwise return the number
* of bytes ( maximum @ req - > wb_bytes ) that can be coalesced .
2011-03-01 04:34:14 +03:00
*/
2014-05-15 19:56:43 +04:00
static size_t
2011-03-01 04:34:14 +03:00
filelayout_pg_test ( struct nfs_pageio_descriptor * pgio , struct nfs_page * prev ,
struct nfs_page * req )
{
2014-05-15 19:56:51 +04:00
unsigned int size ;
2011-03-01 04:34:14 +03:00
u64 p_stripe , r_stripe ;
2014-05-15 19:56:56 +04:00
u32 stripe_offset ;
u64 segment_offset = pgio - > pg_lseg - > pls_range . offset ;
u32 stripe_unit = FILELAYOUT_LSEG ( pgio - > pg_lseg ) - > stripe_unit ;
2011-03-01 04:34:14 +03:00
2014-05-15 19:56:51 +04:00
/* calls nfs_generic_pg_test */
size = pnfs_generic_pg_test ( pgio , prev , req ) ;
if ( ! size )
2014-05-15 19:56:43 +04:00
return 0 ;
2011-05-25 21:54:40 +04:00
2014-05-15 19:56:56 +04:00
/* see if req and prev are in the same stripe */
2014-05-15 19:56:51 +04:00
if ( prev ) {
2014-05-15 19:56:56 +04:00
p_stripe = ( u64 ) req_offset ( prev ) - segment_offset ;
r_stripe = ( u64 ) req_offset ( req ) - segment_offset ;
2014-05-15 19:56:51 +04:00
do_div ( p_stripe , stripe_unit ) ;
do_div ( r_stripe , stripe_unit ) ;
2011-03-01 04:34:14 +03:00
2014-05-15 19:56:51 +04:00
if ( p_stripe ! = r_stripe )
return 0 ;
}
2014-05-15 19:56:56 +04:00
/* calculate remaining bytes in the current stripe */
div_u64_rem ( ( u64 ) req_offset ( req ) - segment_offset ,
stripe_unit ,
& stripe_offset ) ;
WARN_ON_ONCE ( stripe_offset > stripe_unit ) ;
if ( stripe_offset > = stripe_unit )
return 0 ;
return min ( stripe_unit - ( unsigned int ) stripe_offset , size ) ;
2011-03-01 04:34:14 +03:00
}
2017-03-21 01:07:02 +03:00
static struct pnfs_layout_segment *
fl_pnfs_update_layout ( struct inode * ino ,
struct nfs_open_context * ctx ,
loff_t pos ,
u64 count ,
enum pnfs_iomode iomode ,
bool strict_iomode ,
gfp_t gfp_flags )
{
struct pnfs_layout_segment * lseg = NULL ;
struct pnfs_layout_hdr * lo ;
struct nfs4_filelayout_segment * fl ;
int status ;
lseg = pnfs_update_layout ( ino , ctx , pos , count , iomode , strict_iomode ,
gfp_flags ) ;
2022-05-14 17:08:13 +03:00
if ( IS_ERR ( lseg ) ) {
/* Fall back to MDS on recoverable errors */
if ( ! nfs_error_is_fatal_on_server ( PTR_ERR ( lseg ) ) )
lseg = NULL ;
goto out ;
} else if ( ! lseg )
2017-03-21 01:07:02 +03:00
goto out ;
lo = NFS_I ( ino ) - > layout ;
fl = FILELAYOUT_LSEG ( lseg ) ;
status = filelayout_check_deviceid ( lo , fl , gfp_flags ) ;
2017-04-21 22:35:51 +03:00
if ( status ) {
pnfs_put_lseg ( lseg ) ;
2019-05-07 20:41:49 +03:00
lseg = NULL ;
2017-04-21 22:35:51 +03:00
}
2017-03-21 01:07:02 +03:00
out :
return lseg ;
}
2012-03-11 21:11:00 +04:00
static void
2011-06-14 02:22:38 +04:00
filelayout_pg_init_read ( struct nfs_pageio_descriptor * pgio ,
struct nfs_page * req )
{
2017-04-25 17:56:19 +03:00
pnfs_generic_pg_check_layout ( pgio ) ;
2015-12-03 21:57:48 +03:00
if ( ! pgio - > pg_lseg ) {
2017-03-21 01:07:02 +03:00
pgio - > pg_lseg = fl_pnfs_update_layout ( pgio - > pg_inode ,
2019-04-07 20:59:11 +03:00
nfs_req_openctx ( req ) ,
2017-03-21 01:07:02 +03:00
0 ,
NFS4_MAX_UINT64 ,
IOMODE_READ ,
false ,
GFP_KERNEL ) ;
2015-12-03 21:57:48 +03:00
if ( IS_ERR ( pgio - > pg_lseg ) ) {
pgio - > pg_error = PTR_ERR ( pgio - > pg_lseg ) ;
pgio - > pg_lseg = NULL ;
return ;
}
}
2011-06-14 02:22:38 +04:00
/* If no lseg, fall back to read through mds */
if ( pgio - > pg_lseg = = NULL )
2011-07-13 23:59:57 +04:00
nfs_pageio_reset_read_mds ( pgio ) ;
2011-06-14 02:22:38 +04:00
}
2012-03-11 21:11:00 +04:00
static void
2011-06-14 02:22:38 +04:00
filelayout_pg_init_write ( struct nfs_pageio_descriptor * pgio ,
struct nfs_page * req )
{
2017-04-25 17:56:19 +03:00
pnfs_generic_pg_check_layout ( pgio ) ;
2015-12-03 21:57:48 +03:00
if ( ! pgio - > pg_lseg ) {
2017-03-21 01:07:02 +03:00
pgio - > pg_lseg = fl_pnfs_update_layout ( pgio - > pg_inode ,
2019-04-07 20:59:11 +03:00
nfs_req_openctx ( req ) ,
2017-03-21 01:07:02 +03:00
0 ,
NFS4_MAX_UINT64 ,
IOMODE_RW ,
false ,
GFP_NOFS ) ;
2015-12-03 21:57:48 +03:00
if ( IS_ERR ( pgio - > pg_lseg ) ) {
pgio - > pg_error = PTR_ERR ( pgio - > pg_lseg ) ;
pgio - > pg_lseg = NULL ;
return ;
}
}
2011-06-14 02:22:38 +04:00
/* If no lseg, fall back to write through mds */
if ( pgio - > pg_lseg = = NULL )
2020-03-21 16:50:05 +03:00
nfs_pageio_reset_write_mds ( pgio ) ;
2011-06-14 02:22:38 +04:00
}
2011-06-10 21:30:23 +04:00
static const struct nfs_pageio_ops filelayout_pg_read_ops = {
2011-06-14 02:22:38 +04:00
. pg_init = filelayout_pg_init_read ,
2011-06-10 21:30:23 +04:00
. pg_test = filelayout_pg_test ,
2011-07-13 23:58:28 +04:00
. pg_doio = pnfs_generic_pg_readpages ,
2014-09-10 23:48:01 +04:00
. pg_cleanup = pnfs_generic_pg_cleanup ,
2011-06-10 21:30:23 +04:00
} ;
static const struct nfs_pageio_ops filelayout_pg_write_ops = {
2011-06-14 02:22:38 +04:00
. pg_init = filelayout_pg_init_write ,
2011-06-10 21:30:23 +04:00
. pg_test = filelayout_pg_test ,
2011-07-13 23:59:19 +04:00
. pg_doio = pnfs_generic_pg_writepages ,
2014-09-10 23:48:01 +04:00
. pg_cleanup = pnfs_generic_pg_cleanup ,
2011-06-10 21:30:23 +04:00
} ;
2011-03-23 16:27:53 +03:00
static u32 select_bucket_index ( struct nfs4_filelayout_segment * fl , u32 j )
{
if ( fl - > stripe_type = = STRIPE_SPARSE )
return nfs4_fl_calc_ds_index ( & fl - > generic_hdr , j ) ;
else
return j ;
}
2014-07-03 09:07:45 +04:00
static void
filelayout_mark_request_commit ( struct nfs_page * req ,
struct pnfs_layout_segment * lseg ,
2014-09-06 02:20:21 +04:00
struct nfs_commit_info * cinfo ,
u32 ds_commit_idx )
2014-07-03 09:07:45 +04:00
2011-03-23 16:27:53 +03:00
{
struct nfs4_filelayout_segment * fl = FILELAYOUT_LSEG ( lseg ) ;
u32 i , j ;
2014-07-03 09:07:45 +04:00
if ( fl - > commit_through_mds ) {
2016-01-16 00:54:15 +03:00
nfs_request_add_commit_list ( req , cinfo ) ;
2015-02-18 01:58:15 +03:00
} else {
/* Note that we are calling nfs4_fl_calc_j_index on each page
* that ends up being committed to a data server . An attractive
* alternative is to add a field to nfs_write_data and nfs_page
* to store the value calculated in filelayout_write_pagelist
* and just use that here .
2012-03-09 02:29:35 +04:00
*/
2015-02-18 01:58:15 +03:00
j = nfs4_fl_calc_j_index ( lseg , req_offset ( req ) ) ;
i = select_bucket_index ( fl , j ) ;
pnfs_layout_mark_request_commit ( req , lseg , cinfo , i ) ;
2011-03-23 16:27:53 +03:00
}
2012-03-16 01:16:40 +04:00
}
2011-03-23 16:27:53 +03:00
static u32 calc_ds_index_from_commit ( struct pnfs_layout_segment * lseg , u32 i )
{
struct nfs4_filelayout_segment * flseg = FILELAYOUT_LSEG ( lseg ) ;
if ( flseg - > stripe_type = = STRIPE_SPARSE )
return i ;
else
return nfs4_fl_calc_ds_index ( lseg , i ) ;
}
static struct nfs_fh *
select_ds_fh_from_commit ( struct pnfs_layout_segment * lseg , u32 i )
{
struct nfs4_filelayout_segment * flseg = FILELAYOUT_LSEG ( lseg ) ;
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 ;
}
return flseg - > fh_array [ i ] ;
}
2012-04-20 22:47:39 +04:00
static int filelayout_initiate_commit ( struct nfs_commit_data * data , int how )
2011-03-23 16:27:53 +03:00
{
struct pnfs_layout_segment * lseg = data - > lseg ;
struct nfs4_pnfs_ds * ds ;
2013-09-06 22:14:00 +04:00
struct rpc_clnt * ds_clnt ;
2011-03-23 16:27:53 +03:00
u32 idx ;
struct nfs_fh * fh ;
idx = calc_ds_index_from_commit ( lseg , data - > ds_commit_index ) ;
ds = nfs4_fl_prepare_ds ( lseg , idx ) ;
2013-09-06 22:14:00 +04:00
if ( ! ds )
goto out_err ;
ds_clnt = nfs4_find_or_create_ds_client ( ds - > ds_clp , data - > inode ) ;
if ( IS_ERR ( ds_clnt ) )
goto out_err ;
2012-04-28 01:53:51 +04:00
dprintk ( " %s ino %lu, how %d cl_count %d \n " , __func__ ,
2017-10-20 12:53:38 +03:00
data - > inode - > i_ino , how , refcount_read ( & ds - > ds_clp - > cl_count ) ) ;
2012-04-20 22:47:39 +04:00
data - > commit_done_cb = filelayout_commit_done_cb ;
2017-10-20 12:53:38 +03:00
refcount_inc ( & ds - > ds_clp - > cl_count ) ;
2011-03-23 16:27:53 +03:00
data - > ds_clp = ds - > ds_clp ;
fh = select_ds_fh_from_commit ( lseg , data - > ds_commit_index ) ;
if ( fh )
data - > args . fh = fh ;
2014-06-09 03:10:14 +04:00
return nfs_initiate_commit ( ds_clnt , data , NFS_PROTO ( data - > inode ) ,
2012-04-28 01:53:44 +04:00
& filelayout_commit_call_ops , how ,
RPC_TASK_SOFTCONN ) ;
2013-09-06 22:14:00 +04:00
out_err :
2014-12-11 23:34:59 +03:00
pnfs_generic_prepare_to_resend_writes ( data ) ;
pnfs_generic_commit_release ( data ) ;
2013-09-06 22:14:00 +04:00
return - EAGAIN ;
2011-03-23 16:27:53 +03:00
}
static int
filelayout_commit_pagelist ( struct inode * inode , struct list_head * mds_pages ,
2012-04-20 22:47:53 +04:00
int how , struct nfs_commit_info * cinfo )
2011-03-23 16:27:53 +03:00
{
2014-12-11 23:34:59 +03:00
return pnfs_generic_commit_pagelist ( inode , mds_pages , how , cinfo ,
filelayout_initiate_commit ) ;
2011-03-23 16:27:53 +03:00
}
2014-12-11 23:34:59 +03:00
2014-09-03 08:27:57 +04:00
static struct nfs4_deviceid_node *
filelayout_alloc_deviceid_node ( struct nfs_server * server ,
struct pnfs_device * pdev , gfp_t gfp_flags )
{
struct nfs4_file_layout_dsaddr * dsaddr ;
dsaddr = nfs4_fl_alloc_deviceid_node ( server , pdev , gfp_flags ) ;
if ( ! dsaddr )
return NULL ;
return & dsaddr - > id_node ;
}
2011-03-23 16:27:53 +03:00
2011-05-20 15:47:33 +04:00
static void
2015-03-10 00:25:14 +03:00
filelayout_free_deviceid_node ( struct nfs4_deviceid_node * d )
2011-05-20 15:47:33 +04:00
{
nfs4_fl_free_deviceid ( container_of ( d , struct nfs4_file_layout_dsaddr , id_node ) ) ;
}
2012-04-20 22:47:38 +04:00
static struct pnfs_layout_hdr *
filelayout_alloc_layout_hdr ( struct inode * inode , gfp_t gfp_flags )
{
struct nfs4_filelayout * flo ;
flo = kzalloc ( sizeof ( * flo ) , gfp_flags ) ;
2020-03-19 20:36:36 +03:00
if ( flo = = NULL )
return NULL ;
pnfs_init_ds_commit_info ( & flo - > commit_info ) ;
2020-03-21 18:13:05 +03:00
flo - > commit_info . ops = & filelayout_commit_ops ;
2020-03-19 20:36:36 +03:00
return & flo - > generic_hdr ;
2012-04-20 22:47:38 +04:00
}
static void
filelayout_free_layout_hdr ( struct pnfs_layout_hdr * lo )
{
2020-02-19 01:14:40 +03:00
kfree_rcu ( FILELAYOUT_FROM_HDR ( lo ) , generic_hdr . plh_rcu ) ;
2012-04-20 22:47:38 +04:00
}
2012-04-20 22:47:53 +04:00
static struct pnfs_ds_commit_info *
filelayout_get_ds_info ( struct inode * inode )
{
2012-04-24 22:50:34 +04:00
struct pnfs_layout_hdr * layout = NFS_I ( inode ) - > layout ;
if ( layout = = NULL )
return NULL ;
else
return & FILELAYOUT_FROM_HDR ( layout ) - > commit_info ;
2012-04-20 22:47:53 +04:00
}
2020-03-21 01:34:33 +03:00
static void
filelayout_setup_ds_info ( struct pnfs_ds_commit_info * fl_cinfo ,
struct pnfs_layout_segment * lseg )
{
struct nfs4_filelayout_segment * fl = FILELAYOUT_LSEG ( lseg ) ;
struct inode * inode = lseg - > pls_layout - > plh_inode ;
struct pnfs_commit_array * array , * new ;
unsigned int size = ( fl - > stripe_type = = STRIPE_SPARSE ) ?
fl - > dsaddr - > ds_num : fl - > dsaddr - > stripe_count ;
2022-03-22 00:27:14 +03:00
new = pnfs_alloc_commit_array ( size , nfs_io_gfp_mask ( ) ) ;
2020-03-21 01:34:33 +03:00
if ( new ) {
spin_lock ( & inode - > i_lock ) ;
array = pnfs_add_commit_array ( fl_cinfo , new , lseg ) ;
spin_unlock ( & inode - > i_lock ) ;
if ( array ! = new )
pnfs_free_commit_array ( new ) ;
}
}
2020-03-20 23:04:06 +03:00
static void
filelayout_release_ds_info ( struct pnfs_ds_commit_info * fl_cinfo ,
struct inode * inode )
{
spin_lock ( & inode - > i_lock ) ;
pnfs_generic_ds_cinfo_destroy ( fl_cinfo ) ;
spin_unlock ( & inode - > i_lock ) ;
}
2020-03-21 18:13:05 +03:00
static const struct pnfs_commit_ops filelayout_commit_ops = {
. setup_ds_info = filelayout_setup_ds_info ,
. release_ds_info = filelayout_release_ds_info ,
. mark_request_commit = filelayout_mark_request_commit ,
. clear_request_commit = pnfs_generic_clear_request_commit ,
. scan_commit_lists = pnfs_generic_scan_commit_lists ,
. recover_commit_reqs = pnfs_generic_recover_commit_reqs ,
. search_commit_reqs = pnfs_generic_search_commit_reqs ,
. commit_pagelist = filelayout_commit_pagelist ,
} ;
2020-03-20 23:04:06 +03:00
2010-10-20 08:18:00 +04:00
static struct pnfs_layoutdriver_type filelayout_type = {
2011-03-01 04:34:21 +03:00
. id = LAYOUT_NFSV4_1_FILES ,
. name = " LAYOUT_NFSV4_1_FILES " ,
. owner = THIS_MODULE ,
2019-09-11 00:14:30 +03:00
. flags = PNFS_LAYOUTGET_ON_OPEN ,
2018-09-03 20:12:15 +03:00
. max_layoutget_response = 4096 , /* 1 page or so... */
2012-04-20 22:47:38 +04:00
. alloc_layout_hdr = filelayout_alloc_layout_hdr ,
. free_layout_hdr = filelayout_free_layout_hdr ,
2011-03-01 04:34:21 +03:00
. alloc_lseg = filelayout_alloc_lseg ,
. free_lseg = filelayout_free_lseg ,
2011-06-10 21:30:23 +04:00
. pg_read_ops = & filelayout_pg_read_ops ,
. pg_write_ops = & filelayout_pg_write_ops ,
2012-04-20 22:47:53 +04:00
. get_ds_info = & filelayout_get_ds_info ,
2011-03-01 04:34:19 +03:00
. read_pagelist = filelayout_read_pagelist ,
2011-03-03 18:13:45 +03:00
. write_pagelist = filelayout_write_pagelist ,
2014-09-03 08:27:57 +04:00
. alloc_deviceid_node = filelayout_alloc_deviceid_node ,
2015-03-10 00:25:14 +03:00
. free_deviceid_node = filelayout_free_deviceid_node ,
2015-03-25 21:14:42 +03:00
. sync = pnfs_nfs_generic_sync ,
2010-10-20 08:18:00 +04:00
} ;
static int __init nfs4filelayout_init ( void )
{
printk ( KERN_INFO " %s: NFSv4 File Layout Driver Registering... \n " ,
__func__ ) ;
return pnfs_register_layoutdriver ( & filelayout_type ) ;
}
static void __exit nfs4filelayout_exit ( void )
{
printk ( KERN_INFO " %s: NFSv4 File Layout Driver Unregistering... \n " ,
__func__ ) ;
pnfs_unregister_layoutdriver ( & filelayout_type ) ;
}
2011-07-16 03:18:42 +04:00
MODULE_ALIAS ( " nfs-layouttype4-1 " ) ;
2010-10-20 08:18:00 +04:00
module_init ( nfs4filelayout_init ) ;
module_exit ( nfs4filelayout_exit ) ;