Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
301933a0
Commit
301933a0
authored
Jun 17, 2009
by
Trond Myklebust
Browse files
Options
Browse Files
Download
Plain Diff
Merge commit 'linux-pnfs/nfs41-for-2.6.31' into nfsv41-for-2.6.31
parents
3fe0344f
68f3f901
Changes
38
Show whitespace changes
Inline
Side-by-side
Showing
38 changed files
with
4589 additions
and
374 deletions
+4589
-374
fs/nfs/Kconfig
fs/nfs/Kconfig
+9
-0
fs/nfs/callback.c
fs/nfs/callback.c
+179
-35
fs/nfs/callback.h
fs/nfs/callback.h
+61
-7
fs/nfs/callback_proc.c
fs/nfs/callback_proc.c
+127
-0
fs/nfs/callback_xdr.c
fs/nfs/callback_xdr.c
+258
-22
fs/nfs/client.c
fs/nfs/client.c
+160
-22
fs/nfs/direct.c
fs/nfs/direct.c
+9
-0
fs/nfs/internal.h
fs/nfs/internal.h
+62
-0
fs/nfs/nfs4_fs.h
fs/nfs/nfs4_fs.h
+35
-2
fs/nfs/nfs4proc.c
fs/nfs/nfs4proc.c
+1238
-49
fs/nfs/nfs4renewd.c
fs/nfs/nfs4renewd.c
+4
-2
fs/nfs/nfs4state.c
fs/nfs/nfs4state.c
+135
-18
fs/nfs/nfs4xdr.c
fs/nfs/nfs4xdr.c
+940
-132
fs/nfs/read.c
fs/nfs/read.c
+30
-3
fs/nfs/super.c
fs/nfs/super.c
+12
-1
fs/nfs/unlink.c
fs/nfs/unlink.c
+19
-1
fs/nfs/write.c
fs/nfs/write.c
+29
-2
include/linux/nfs4.h
include/linux/nfs4.h
+18
-0
include/linux/nfs_fs_sb.h
include/linux/nfs_fs_sb.h
+66
-1
include/linux/nfs_xdr.h
include/linux/nfs_xdr.h
+171
-0
include/linux/nfsd/state.h
include/linux/nfsd/state.h
+0
-1
include/linux/sunrpc/bc_xprt.h
include/linux/sunrpc/bc_xprt.h
+49
-0
include/linux/sunrpc/clnt.h
include/linux/sunrpc/clnt.h
+1
-0
include/linux/sunrpc/sched.h
include/linux/sunrpc/sched.h
+3
-0
include/linux/sunrpc/svc.h
include/linux/sunrpc/svc.h
+11
-0
include/linux/sunrpc/svcsock.h
include/linux/sunrpc/svcsock.h
+2
-0
include/linux/sunrpc/xprt.h
include/linux/sunrpc/xprt.h
+37
-1
net/sunrpc/Makefile
net/sunrpc/Makefile
+1
-0
net/sunrpc/backchannel_rqst.c
net/sunrpc/backchannel_rqst.c
+278
-0
net/sunrpc/bc_svc.c
net/sunrpc/bc_svc.c
+81
-0
net/sunrpc/clnt.c
net/sunrpc/clnt.c
+136
-7
net/sunrpc/sched.c
net/sunrpc/sched.c
+1
-1
net/sunrpc/stats.c
net/sunrpc/stats.c
+5
-3
net/sunrpc/sunrpc.h
net/sunrpc/sunrpc.h
+37
-0
net/sunrpc/svc.c
net/sunrpc/svc.c
+104
-30
net/sunrpc/svcsock.c
net/sunrpc/svcsock.c
+39
-0
net/sunrpc/xprt.c
net/sunrpc/xprt.c
+46
-14
net/sunrpc/xprtsock.c
net/sunrpc/xprtsock.c
+196
-20
No files found.
fs/nfs/Kconfig
View file @
301933a0
...
...
@@ -74,6 +74,15 @@ config NFS_V4
If unsure, say N.
config NFS_V4_1
bool "NFS client support for NFSv4.1 (DEVELOPER ONLY)"
depends on NFS_V4 && EXPERIMENTAL
help
This option enables support for minor version 1 of the NFSv4 protocol
(draft-ietf-nfsv4-minorversion1) in the kernel's NFS client.
Unless you're an NFS developer, say N.
config ROOT_NFS
bool "Root file system on NFS"
depends on NFS_FS=y && IP_PNP
...
...
fs/nfs/callback.c
View file @
301933a0
...
...
@@ -17,6 +17,9 @@
#include <linux/freezer.h>
#include <linux/kthread.h>
#include <linux/sunrpc/svcauth_gss.h>
#if defined(CONFIG_NFS_V4_1)
#include <linux/sunrpc/bc_xprt.h>
#endif
#include <net/inet_sock.h>
...
...
@@ -28,11 +31,12 @@
struct
nfs_callback_data
{
unsigned
int
users
;
struct
svc_serv
*
serv
;
struct
svc_rqst
*
rqst
;
struct
task_struct
*
task
;
};
static
struct
nfs_callback_data
nfs_callback_info
;
static
struct
nfs_callback_data
nfs_callback_info
[
NFS4_MAX_MINOR_VERSION
+
1
]
;
static
DEFINE_MUTEX
(
nfs_callback_mutex
);
static
struct
svc_program
nfs4_callback_program
;
...
...
@@ -56,10 +60,10 @@ module_param_call(callback_tcpport, param_set_port, param_get_int,
&
nfs_callback_set_tcpport
,
0644
);
/*
* This is the callback kernel thread.
* This is the
NFSv4
callback kernel thread.
*/
static
int
nfs_callback_svc
(
void
*
vrqstp
)
nfs
4
_callback_svc
(
void
*
vrqstp
)
{
int
err
,
preverr
=
0
;
struct
svc_rqst
*
rqstp
=
vrqstp
;
...
...
@@ -97,20 +101,12 @@ nfs_callback_svc(void *vrqstp)
}
/*
*
Bring up the callback thread if it is not already up.
*
Prepare to bring up the NFSv4 callback service
*/
int
nfs_callback_up
(
void
)
struct
svc_rqst
*
nfs4_callback_up
(
struct
svc_serv
*
serv
)
{
struct
svc_serv
*
serv
=
NULL
;
int
ret
=
0
;
mutex_lock
(
&
nfs_callback_mutex
);
if
(
nfs_callback_info
.
users
++
||
nfs_callback_info
.
task
!=
NULL
)
goto
out
;
serv
=
svc_create
(
&
nfs4_callback_program
,
NFS4_CALLBACK_BUFSIZE
,
NULL
);
ret
=
-
ENOMEM
;
if
(
!
serv
)
goto
out_err
;
int
ret
;
ret
=
svc_create_xprt
(
serv
,
"tcp"
,
PF_INET
,
nfs_callback_set_tcpport
,
SVC_SOCK_ANONYMOUS
);
...
...
@@ -131,23 +127,168 @@ int nfs_callback_up(void)
goto
out_err
;
#endif
/* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
nfs_callback_info
.
rqst
=
svc_prepare_thread
(
serv
,
&
serv
->
sv_pools
[
0
]);
if
(
IS_ERR
(
nfs_callback_info
.
rqst
))
{
ret
=
PTR_ERR
(
nfs_callback_info
.
rqst
);
nfs_callback_info
.
rqst
=
NULL
;
return
svc_prepare_thread
(
serv
,
&
serv
->
sv_pools
[
0
]);
out_err:
if
(
ret
==
0
)
ret
=
-
ENOMEM
;
return
ERR_PTR
(
ret
);
}
#if defined(CONFIG_NFS_V4_1)
/*
* The callback service for NFSv4.1 callbacks
*/
static
int
nfs41_callback_svc
(
void
*
vrqstp
)
{
struct
svc_rqst
*
rqstp
=
vrqstp
;
struct
svc_serv
*
serv
=
rqstp
->
rq_server
;
struct
rpc_rqst
*
req
;
int
error
;
DEFINE_WAIT
(
wq
);
set_freezable
();
/*
* FIXME: do we really need to run this under the BKL? If so, please
* add a comment about what it's intended to protect.
*/
lock_kernel
();
while
(
!
kthread_should_stop
())
{
prepare_to_wait
(
&
serv
->
sv_cb_waitq
,
&
wq
,
TASK_INTERRUPTIBLE
);
spin_lock_bh
(
&
serv
->
sv_cb_lock
);
if
(
!
list_empty
(
&
serv
->
sv_cb_list
))
{
req
=
list_first_entry
(
&
serv
->
sv_cb_list
,
struct
rpc_rqst
,
rq_bc_list
);
list_del
(
&
req
->
rq_bc_list
);
spin_unlock_bh
(
&
serv
->
sv_cb_lock
);
dprintk
(
"Invoking bc_svc_process()
\n
"
);
error
=
bc_svc_process
(
serv
,
req
,
rqstp
);
dprintk
(
"bc_svc_process() returned w/ error code= %d
\n
"
,
error
);
}
else
{
spin_unlock_bh
(
&
serv
->
sv_cb_lock
);
schedule
();
}
finish_wait
(
&
serv
->
sv_cb_waitq
,
&
wq
);
}
unlock_kernel
();
return
0
;
}
/*
* Bring up the NFSv4.1 callback service
*/
struct
svc_rqst
*
nfs41_callback_up
(
struct
svc_serv
*
serv
,
struct
rpc_xprt
*
xprt
)
{
struct
svc_xprt
*
bc_xprt
;
struct
svc_rqst
*
rqstp
=
ERR_PTR
(
-
ENOMEM
);
dprintk
(
"--> %s
\n
"
,
__func__
);
/* Create a svc_sock for the service */
bc_xprt
=
svc_sock_create
(
serv
,
xprt
->
prot
);
if
(
!
bc_xprt
)
goto
out
;
/*
* Save the svc_serv in the transport so that it can
* be referenced when the session backchannel is initialized
*/
serv
->
bc_xprt
=
bc_xprt
;
xprt
->
bc_serv
=
serv
;
INIT_LIST_HEAD
(
&
serv
->
sv_cb_list
);
spin_lock_init
(
&
serv
->
sv_cb_lock
);
init_waitqueue_head
(
&
serv
->
sv_cb_waitq
);
rqstp
=
svc_prepare_thread
(
serv
,
&
serv
->
sv_pools
[
0
]);
if
(
IS_ERR
(
rqstp
))
svc_sock_destroy
(
bc_xprt
);
out:
dprintk
(
"--> %s return %p
\n
"
,
__func__
,
rqstp
);
return
rqstp
;
}
static
inline
int
nfs_minorversion_callback_svc_setup
(
u32
minorversion
,
struct
svc_serv
*
serv
,
struct
rpc_xprt
*
xprt
,
struct
svc_rqst
**
rqstpp
,
int
(
**
callback_svc
)(
void
*
vrqstp
))
{
if
(
minorversion
)
{
*
rqstpp
=
nfs41_callback_up
(
serv
,
xprt
);
*
callback_svc
=
nfs41_callback_svc
;
}
return
minorversion
;
}
static
inline
void
nfs_callback_bc_serv
(
u32
minorversion
,
struct
rpc_xprt
*
xprt
,
struct
nfs_callback_data
*
cb_info
)
{
if
(
minorversion
)
xprt
->
bc_serv
=
cb_info
->
serv
;
}
#else
static
inline
int
nfs_minorversion_callback_svc_setup
(
u32
minorversion
,
struct
svc_serv
*
serv
,
struct
rpc_xprt
*
xprt
,
struct
svc_rqst
**
rqstpp
,
int
(
**
callback_svc
)(
void
*
vrqstp
))
{
return
0
;
}
static
inline
void
nfs_callback_bc_serv
(
u32
minorversion
,
struct
rpc_xprt
*
xprt
,
struct
nfs_callback_data
*
cb_info
)
{
}
#endif
/* CONFIG_NFS_V4_1 */
/*
* Bring up the callback thread if it is not already up.
*/
int
nfs_callback_up
(
u32
minorversion
,
struct
rpc_xprt
*
xprt
)
{
struct
svc_serv
*
serv
=
NULL
;
struct
svc_rqst
*
rqstp
;
int
(
*
callback_svc
)(
void
*
vrqstp
);
struct
nfs_callback_data
*
cb_info
=
&
nfs_callback_info
[
minorversion
];
char
svc_name
[
12
];
int
ret
=
0
;
int
minorversion_setup
;
mutex_lock
(
&
nfs_callback_mutex
);
if
(
cb_info
->
users
++
||
cb_info
->
task
!=
NULL
)
{
nfs_callback_bc_serv
(
minorversion
,
xprt
,
cb_info
);
goto
out
;
}
serv
=
svc_create
(
&
nfs4_callback_program
,
NFS4_CALLBACK_BUFSIZE
,
NULL
);
if
(
!
serv
)
{
ret
=
-
ENOMEM
;
goto
out_err
;
}
minorversion_setup
=
nfs_minorversion_callback_svc_setup
(
minorversion
,
serv
,
xprt
,
&
rqstp
,
&
callback_svc
);
if
(
!
minorversion_setup
)
{
/* v4.0 callback setup */
rqstp
=
nfs4_callback_up
(
serv
);
callback_svc
=
nfs4_callback_svc
;
}
if
(
IS_ERR
(
rqstp
))
{
ret
=
PTR_ERR
(
rqstp
);
goto
out_err
;
}
svc_sock_update_bufs
(
serv
);
nfs_callback_info
.
task
=
kthread_run
(
nfs_callback_svc
,
nfs_callback_info
.
rqst
,
"nfsv4-svc"
);
if
(
IS_ERR
(
nfs_callback_info
.
task
))
{
ret
=
PTR_ERR
(
nfs_callback_info
.
task
);
svc_exit_thread
(
nfs_callback_info
.
rqst
);
nfs_callback_info
.
rqst
=
NULL
;
nfs_callback_info
.
task
=
NULL
;
sprintf
(
svc_name
,
"nfsv4.%u-svc"
,
minorversion
);
cb_info
->
serv
=
serv
;
cb_info
->
rqst
=
rqstp
;
cb_info
->
task
=
kthread_run
(
callback_svc
,
cb_info
->
rqst
,
svc_name
);
if
(
IS_ERR
(
cb_info
->
task
))
{
ret
=
PTR_ERR
(
cb_info
->
task
);
svc_exit_thread
(
cb_info
->
rqst
);
cb_info
->
rqst
=
NULL
;
cb_info
->
task
=
NULL
;
goto
out_err
;
}
out:
...
...
@@ -164,22 +305,25 @@ int nfs_callback_up(void)
out_err:
dprintk
(
"NFS: Couldn't create callback socket or server thread; "
"err = %d
\n
"
,
ret
);
nfs_callback_info
.
users
--
;
cb_info
->
users
--
;
goto
out
;
}
/*
* Kill the callback thread if it's no longer being used.
*/
void
nfs_callback_down
(
void
)
void
nfs_callback_down
(
int
minorversion
)
{
struct
nfs_callback_data
*
cb_info
=
&
nfs_callback_info
[
minorversion
];
mutex_lock
(
&
nfs_callback_mutex
);
nfs_callback_info
.
users
--
;
if
(
nfs_callback_info
.
users
==
0
&&
nfs_callback_info
.
task
!=
NULL
)
{
kthread_stop
(
nfs_callback_info
.
task
);
svc_exit_thread
(
nfs_callback_info
.
rqst
);
nfs_callback_info
.
rqst
=
NULL
;
nfs_callback_info
.
task
=
NULL
;
cb_info
->
users
--
;
if
(
cb_info
->
users
==
0
&&
cb_info
->
task
!=
NULL
)
{
kthread_stop
(
cb_info
->
task
);
svc_exit_thread
(
cb_info
->
rqst
);
cb_info
->
serv
=
NULL
;
cb_info
->
rqst
=
NULL
;
cb_info
->
task
=
NULL
;
}
mutex_unlock
(
&
nfs_callback_mutex
);
}
...
...
fs/nfs/callback.h
View file @
301933a0
...
...
@@ -20,13 +20,24 @@ enum nfs4_callback_procnum {
enum
nfs4_callback_opnum
{
OP_CB_GETATTR
=
3
,
OP_CB_RECALL
=
4
,
/* Callback operations new to NFSv4.1 */
OP_CB_LAYOUTRECALL
=
5
,
OP_CB_NOTIFY
=
6
,
OP_CB_PUSH_DELEG
=
7
,
OP_CB_RECALL_ANY
=
8
,
OP_CB_RECALLABLE_OBJ_AVAIL
=
9
,
OP_CB_RECALL_SLOT
=
10
,
OP_CB_SEQUENCE
=
11
,
OP_CB_WANTS_CANCELLED
=
12
,
OP_CB_NOTIFY_LOCK
=
13
,
OP_CB_NOTIFY_DEVICEID
=
14
,
OP_CB_ILLEGAL
=
10044
,
};
struct
cb_compound_hdr_arg
{
unsigned
int
taglen
;
const
char
*
tag
;
unsigned
int
callback_ident
;
unsigned
int
minorversion
;
unsigned
nops
;
};
...
...
@@ -59,16 +70,59 @@ struct cb_recallargs {
uint32_t
truncate
;
};
#if defined(CONFIG_NFS_V4_1)
struct
referring_call
{
uint32_t
rc_sequenceid
;
uint32_t
rc_slotid
;
};
struct
referring_call_list
{
struct
nfs4_sessionid
rcl_sessionid
;
uint32_t
rcl_nrefcalls
;
struct
referring_call
*
rcl_refcalls
;
};
struct
cb_sequenceargs
{
struct
sockaddr
*
csa_addr
;
struct
nfs4_sessionid
csa_sessionid
;
uint32_t
csa_sequenceid
;
uint32_t
csa_slotid
;
uint32_t
csa_highestslotid
;
uint32_t
csa_cachethis
;
uint32_t
csa_nrclists
;
struct
referring_call_list
*
csa_rclists
;
};
struct
cb_sequenceres
{
__be32
csr_status
;
struct
nfs4_sessionid
csr_sessionid
;
uint32_t
csr_sequenceid
;
uint32_t
csr_slotid
;
uint32_t
csr_highestslotid
;
uint32_t
csr_target_highestslotid
;
};
extern
unsigned
nfs4_callback_sequence
(
struct
cb_sequenceargs
*
args
,
struct
cb_sequenceres
*
res
);
#endif
/* CONFIG_NFS_V4_1 */
extern
__be32
nfs4_callback_getattr
(
struct
cb_getattrargs
*
args
,
struct
cb_getattrres
*
res
);
extern
__be32
nfs4_callback_recall
(
struct
cb_recallargs
*
args
,
void
*
dummy
);
#ifdef CONFIG_NFS_V4
extern
int
nfs_callback_up
(
void
);
extern
void
nfs_callback_down
(
void
);
#else
#define nfs_callback_up() (0)
#define nfs_callback_down() do {} while(0)
#endif
extern
int
nfs_callback_up
(
u32
minorversion
,
struct
rpc_xprt
*
xprt
);
extern
void
nfs_callback_down
(
int
minorversion
);
#endif
/* CONFIG_NFS_V4 */
/*
* nfs41: Callbacks are expected to not cause substantial latency,
* so we limit their concurrency to 1 by setting up the maximum number
* of slots for the backchannel.
*/
#define NFS41_BC_MIN_CALLBACKS 1
#define NFS41_BC_MAX_CALLBACKS 1
extern
unsigned
int
nfs_callback_set_tcpport
;
extern
unsigned
short
nfs_callback_tcpport
;
...
...
fs/nfs/callback_proc.c
View file @
301933a0
...
...
@@ -101,3 +101,130 @@ __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy)
dprintk
(
"%s: exit with status = %d
\n
"
,
__func__
,
ntohl
(
res
));
return
res
;
}
#if defined(CONFIG_NFS_V4_1)
/*
* Validate the sequenceID sent by the server.
* Return success if the sequenceID is one more than what we last saw on
* this slot, accounting for wraparound. Increments the slot's sequence.
*
* We don't yet implement a duplicate request cache, so at this time
* we will log replays, and process them as if we had not seen them before,
* but we don't bump the sequence in the slot. Not too worried about it,
* since we only currently implement idempotent callbacks anyway.
*
* We have a single slot backchannel at this time, so we don't bother
* checking the used_slots bit array on the table. The lower layer guarantees
* a single outstanding callback request at a time.
*/
static
int
validate_seqid
(
struct
nfs4_slot_table
*
tbl
,
u32
slotid
,
u32
seqid
)
{
struct
nfs4_slot
*
slot
;
dprintk
(
"%s enter. slotid %d seqid %d
\n
"
,
__func__
,
slotid
,
seqid
);
if
(
slotid
>
NFS41_BC_MAX_CALLBACKS
)
return
htonl
(
NFS4ERR_BADSLOT
);
slot
=
tbl
->
slots
+
slotid
;
dprintk
(
"%s slot table seqid: %d
\n
"
,
__func__
,
slot
->
seq_nr
);
/* Normal */
if
(
likely
(
seqid
==
slot
->
seq_nr
+
1
))
{
slot
->
seq_nr
++
;
return
htonl
(
NFS4_OK
);
}
/* Replay */
if
(
seqid
==
slot
->
seq_nr
)
{
dprintk
(
"%s seqid %d is a replay - no DRC available
\n
"
,
__func__
,
seqid
);
return
htonl
(
NFS4_OK
);
}
/* Wraparound */
if
(
seqid
==
1
&&
(
slot
->
seq_nr
+
1
)
==
0
)
{
slot
->
seq_nr
=
1
;
return
htonl
(
NFS4_OK
);
}
/* Misordered request */
return
htonl
(
NFS4ERR_SEQ_MISORDERED
);
}
/*
* Returns a pointer to a held 'struct nfs_client' that matches the server's
* address, major version number, and session ID. It is the caller's
* responsibility to release the returned reference.
*
* Returns NULL if there are no connections with sessions, or if no session
* matches the one of interest.
*/
static
struct
nfs_client
*
find_client_with_session
(
const
struct
sockaddr
*
addr
,
u32
nfsversion
,
struct
nfs4_sessionid
*
sessionid
)
{
struct
nfs_client
*
clp
;
clp
=
nfs_find_client
(
addr
,
4
);
if
(
clp
==
NULL
)
return
NULL
;
do
{
struct
nfs_client
*
prev
=
clp
;
if
(
clp
->
cl_session
!=
NULL
)
{
if
(
memcmp
(
clp
->
cl_session
->
sess_id
.
data
,
sessionid
->
data
,
NFS4_MAX_SESSIONID_LEN
)
==
0
)
{
/* Returns a held reference to clp */
return
clp
;
}
}
clp
=
nfs_find_client_next
(
prev
);
nfs_put_client
(
prev
);
}
while
(
clp
!=
NULL
);
return
NULL
;
}
/* FIXME: referring calls should be processed */
unsigned
nfs4_callback_sequence
(
struct
cb_sequenceargs
*
args
,
struct
cb_sequenceres
*
res
)
{
struct
nfs_client
*
clp
;
int
i
,
status
;
for
(
i
=
0
;
i
<
args
->
csa_nrclists
;
i
++
)
kfree
(
args
->
csa_rclists
[
i
].
rcl_refcalls
);
kfree
(
args
->
csa_rclists
);
status
=
htonl
(
NFS4ERR_BADSESSION
);
clp
=
find_client_with_session
(
args
->
csa_addr
,
4
,
&
args
->
csa_sessionid
);
if
(
clp
==
NULL
)
goto
out
;
status
=
validate_seqid
(
&
clp
->
cl_session
->
bc_slot_table
,
args
->
csa_slotid
,
args
->
csa_sequenceid
);
if
(
status
)
goto
out_putclient
;
memcpy
(
&
res
->
csr_sessionid
,
&
args
->
csa_sessionid
,
sizeof
(
res
->
csr_sessionid
));
res
->
csr_sequenceid
=
args
->
csa_sequenceid
;
res
->
csr_slotid
=
args
->
csa_slotid
;
res
->
csr_highestslotid
=
NFS41_BC_MAX_CALLBACKS
-
1
;
res
->
csr_target_highestslotid
=
NFS41_BC_MAX_CALLBACKS
-
1
;
out_putclient:
nfs_put_client
(
clp
);
out:
dprintk
(
"%s: exit with status = %d
\n
"
,
__func__
,
ntohl
(
status
));
res
->
csr_status
=
status
;
return
res
->
csr_status
;
}
#endif
/* CONFIG_NFS_V4_1 */
fs/nfs/callback_xdr.c
View file @
301933a0
...
...
@@ -20,6 +20,11 @@
2 + 2 + 3 + 3)
#define CB_OP_RECALL_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ)
#if defined(CONFIG_NFS_V4_1)
#define CB_OP_SEQUENCE_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ + \
4 + 1 + 3)
#endif
/* CONFIG_NFS_V4_1 */
#define NFSDBG_FACILITY NFSDBG_CALLBACK
typedef
__be32
(
*
callback_process_op_t
)(
void
*
,
void
*
);
...
...
@@ -132,7 +137,6 @@ static __be32 decode_stateid(struct xdr_stream *xdr, nfs4_stateid *stateid)
static
__be32
decode_compound_hdr_arg
(
struct
xdr_stream
*
xdr
,
struct
cb_compound_hdr_arg
*
hdr
)
{
__be32
*
p
;
unsigned
int
minor_version
;
__be32
status
;
status
=
decode_string
(
xdr
,
&
hdr
->
taglen
,
&
hdr
->
tag
);
...
...
@@ -147,15 +151,19 @@ static __be32 decode_compound_hdr_arg(struct xdr_stream *xdr, struct cb_compound
p
=
read_buf
(
xdr
,
12
);
if
(
unlikely
(
p
==
NULL
))
return
htonl
(
NFS4ERR_RESOURCE
);
minor_version
=
ntohl
(
*
p
++
);
/* Check minor version is zero. */
if
(
minor_version
!=
0
)
{
printk
(
KERN_WARNING
"%s: NFSv4 server callback with illegal minor version %u!
\n
"
,
__func__
,
minor_version
);
hdr
->
minorversion
=
ntohl
(
*
p
++
);
/* Check minor version is zero or one. */
if
(
hdr
->
minorversion
<=
1
)
{
p
++
;
/* skip callback_ident */
}
else
{
printk
(
KERN_WARNING
"%s: NFSv4 server callback with "
"illegal minor version %u!
\n
"
,
__func__
,
hdr
->
minorversion
);
return
htonl
(
NFS4ERR_MINOR_VERS_MISMATCH
);
}
hdr
->
callback_ident
=
ntohl
(
*
p
++
);
hdr
->
nops
=
ntohl
(
*
p
);
dprintk
(
"%s: minorversion %d nops %d
\n
"
,
__func__
,
hdr
->
minorversion
,
hdr
->
nops
);
return
0
;
}
...
...
@@ -204,6 +212,122 @@ static __be32 decode_recall_args(struct svc_rqst *rqstp, struct xdr_stream *xdr,
return
status
;
}
#if defined(CONFIG_NFS_V4_1)
static
unsigned
decode_sessionid
(
struct
xdr_stream
*
xdr
,
struct
nfs4_sessionid
*
sid
)
{
uint32_t
*
p
;
int
len
=
NFS4_MAX_SESSIONID_LEN
;
p
=
read_buf
(
xdr
,
len
);
if
(
unlikely
(
p
==
NULL
))
return
htonl
(
NFS4ERR_RESOURCE
);;
memcpy
(
sid
->
data
,
p
,
len
);
return
0
;
}
static
unsigned
decode_rc_list
(
struct
xdr_stream
*
xdr
,
struct
referring_call_list
*
rc_list
)
{
uint32_t
*
p
;
int
i
;
unsigned
status
;
status
=
decode_sessionid
(
xdr
,
&
rc_list
->
rcl_sessionid
);
if
(
status
)
goto
out
;
status
=
htonl
(
NFS4ERR_RESOURCE
);
p
=
read_buf
(
xdr
,
sizeof
(
uint32_t
));
if
(
unlikely
(
p
==
NULL
))
goto
out
;
rc_list
->
rcl_nrefcalls
=
ntohl
(
*
p
++
);
if
(
rc_list
->
rcl_nrefcalls
)
{
p
=
read_buf
(
xdr
,
rc_list
->
rcl_nrefcalls
*
2
*
sizeof
(
uint32_t
));
if
(
unlikely
(
p
==
NULL
))
goto
out
;
rc_list
->
rcl_refcalls
=
kmalloc
(
rc_list
->
rcl_nrefcalls
*
sizeof
(
*
rc_list
->
rcl_refcalls
),
GFP_KERNEL
);
if
(
unlikely
(
rc_list
->
rcl_refcalls
==
NULL
))
goto
out
;
for
(
i
=
0
;
i
<
rc_list
->
rcl_nrefcalls
;
i
++
)
{
rc_list
->
rcl_refcalls
[
i
].
rc_sequenceid
=
ntohl
(
*
p
++
);
rc_list
->
rcl_refcalls
[
i
].
rc_slotid
=
ntohl
(
*
p
++
);
}
}
status
=
0
;
out:
return
status
;
}
static
unsigned
decode_cb_sequence_args
(
struct
svc_rqst
*
rqstp
,
struct
xdr_stream
*
xdr
,
struct
cb_sequenceargs
*
args
)
{
uint32_t
*
p
;
int
i
;
unsigned
status
;
status
=
decode_sessionid
(
xdr
,
&
args
->
csa_sessionid
);
if
(
status
)
goto
out
;
status
=
htonl
(
NFS4ERR_RESOURCE
);
p
=
read_buf
(
xdr
,
5
*
sizeof
(
uint32_t
));
if
(
unlikely
(
p
==
NULL
))
goto
out
;
args
->
csa_addr
=
svc_addr
(
rqstp
);
args
->
csa_sequenceid
=
ntohl
(
*
p
++
);
args
->
csa_slotid
=
ntohl
(
*
p
++
);
args
->
csa_highestslotid
=
ntohl
(
*
p
++
);
args
->
csa_cachethis
=
ntohl
(
*
p
++
);
args
->
csa_nrclists
=
ntohl
(
*
p
++
);
args
->
csa_rclists
=
NULL
;
if
(
args
->
csa_nrclists
)
{
args
->
csa_rclists
=
kmalloc
(
args
->
csa_nrclists
*
sizeof
(
*
args
->
csa_rclists
),
GFP_KERNEL
);
if
(
unlikely
(
args
->
csa_rclists
==
NULL
))
goto
out
;
for
(
i
=
0
;
i
<
args
->
csa_nrclists
;
i
++
)
{
status
=
decode_rc_list
(
xdr
,
&
args
->
csa_rclists
[
i
]);
if
(
status
)
goto
out_free
;
}
}
status
=
0
;
dprintk
(
"%s: sessionid %x:%x:%x:%x sequenceid %u slotid %u "
"highestslotid %u cachethis %d nrclists %u
\n
"
,
__func__
,
((
u32
*
)
&
args
->
csa_sessionid
)[
0
],
((
u32
*
)
&
args
->
csa_sessionid
)[
1
],
((
u32
*
)
&
args
->
csa_sessionid
)[
2
],
((
u32
*
)
&
args
->
csa_sessionid
)[
3
],
args
->
csa_sequenceid
,
args
->
csa_slotid
,
args
->
csa_highestslotid
,
args
->
csa_cachethis
,
args
->
csa_nrclists
);
out:
dprintk
(
"%s: exit with status = %d
\n
"
,
__func__
,
ntohl
(
status
));
return
status
;
out_free:
for
(
i
=
0
;
i
<
args
->
csa_nrclists
;
i
++
)
kfree
(
args
->
csa_rclists
[
i
].
rcl_refcalls
);
kfree
(
args
->
csa_rclists
);
goto
out
;
}
#endif
/* CONFIG_NFS_V4_1 */
static
__be32
encode_string
(
struct
xdr_stream
*
xdr
,
unsigned
int
len
,
const
char
*
str
)
{
__be32
*
p
;
...
...
@@ -353,31 +477,134 @@ static __be32 encode_getattr_res(struct svc_rqst *rqstp, struct xdr_stream *xdr,
return
status
;
}
static
__be32
process_op
(
struct
svc_rqst
*
rqstp
,
#if defined(CONFIG_NFS_V4_1)
static
unsigned
encode_sessionid
(
struct
xdr_stream
*
xdr
,
const
struct
nfs4_sessionid
*
sid
)
{
uint32_t
*
p
;
int
len
=
NFS4_MAX_SESSIONID_LEN
;
p
=
xdr_reserve_space
(
xdr
,
len
);
if
(
unlikely
(
p
==
NULL
))
return
htonl
(
NFS4ERR_RESOURCE
);
memcpy
(
p
,
sid
,
len
);
return
0
;
}
static
unsigned
encode_cb_sequence_res
(
struct
svc_rqst
*
rqstp
,
struct
xdr_stream
*
xdr
,
const
struct
cb_sequenceres
*
res
)
{
uint32_t
*
p
;
unsigned
status
=
res
->
csr_status
;
if
(
unlikely
(
status
!=
0
))
goto
out
;
encode_sessionid
(
xdr
,
&
res
->
csr_sessionid
);
p
=
xdr_reserve_space
(
xdr
,
4
*
sizeof
(
uint32_t
));
if
(
unlikely
(
p
==
NULL
))
return
htonl
(
NFS4ERR_RESOURCE
);
*
p
++
=
htonl
(
res
->
csr_sequenceid
);
*
p
++
=
htonl
(
res
->
csr_slotid
);
*
p
++
=
htonl
(
res
->
csr_highestslotid
);
*
p
++
=
htonl
(
res
->
csr_target_highestslotid
);
out:
dprintk
(
"%s: exit with status = %d
\n
"
,
__func__
,
ntohl
(
status
));
return
status
;
}
static
__be32
preprocess_nfs41_op
(
int
nop
,
unsigned
int
op_nr
,
struct
callback_op
**
op
)
{
if
(
op_nr
==
OP_CB_SEQUENCE
)
{
if
(
nop
!=
0
)
return
htonl
(
NFS4ERR_SEQUENCE_POS
);
}
else
{
if
(
nop
==
0
)
return
htonl
(
NFS4ERR_OP_NOT_IN_SESSION
);
}
switch
(
op_nr
)
{
case
OP_CB_GETATTR
:
case
OP_CB_RECALL
:
case
OP_CB_SEQUENCE
:
*
op
=
&
callback_ops
[
op_nr
];
break
;
case
OP_CB_LAYOUTRECALL
:
case
OP_CB_NOTIFY_DEVICEID
:
case
OP_CB_NOTIFY
:
case
OP_CB_PUSH_DELEG
:
case
OP_CB_RECALL_ANY
:
case
OP_CB_RECALLABLE_OBJ_AVAIL
:
case
OP_CB_RECALL_SLOT
:
case
OP_CB_WANTS_CANCELLED
:
case
OP_CB_NOTIFY_LOCK
:
return
htonl
(
NFS4ERR_NOTSUPP
);
default:
return
htonl
(
NFS4ERR_OP_ILLEGAL
);
}
return
htonl
(
NFS_OK
);
}
#else
/* CONFIG_NFS_V4_1 */
static
__be32
preprocess_nfs41_op
(
int
nop
,
unsigned
int
op_nr
,
struct
callback_op
**
op
)
{
return
htonl
(
NFS4ERR_MINOR_VERS_MISMATCH
);
}
#endif
/* CONFIG_NFS_V4_1 */
static
__be32
preprocess_nfs4_op
(
unsigned
int
op_nr
,
struct
callback_op
**
op
)
{
switch
(
op_nr
)
{
case
OP_CB_GETATTR
:
case
OP_CB_RECALL
:
*
op
=
&
callback_ops
[
op_nr
];
break
;
default:
return
htonl
(
NFS4ERR_OP_ILLEGAL
);
}
return
htonl
(
NFS_OK
);
}
static
__be32
process_op
(
uint32_t
minorversion
,
int
nop
,
struct
svc_rqst
*
rqstp
,
struct
xdr_stream
*
xdr_in
,
void
*
argp
,
struct
xdr_stream
*
xdr_out
,
void
*
resp
)
{
struct
callback_op
*
op
=
&
callback_ops
[
0
];
unsigned
int
op_nr
=
OP_CB_ILLEGAL
;
__be32
status
=
0
;
__be32
status
;
long
maxlen
;
__be32
res
;
dprintk
(
"%s: start
\n
"
,
__func__
);
status
=
decode_op_hdr
(
xdr_in
,
&
op_nr
);
if
(
likely
(
status
==
0
))
{
switch
(
op_nr
)
{
case
OP_CB_GETATTR
:
case
OP_CB_RECALL
:
op
=
&
callback_ops
[
op_nr
];
break
;
default:
op_nr
=
OP_CB_ILLEGAL
;
op
=
&
callback_ops
[
0
];
if
(
unlikely
(
status
))
{
status
=
htonl
(
NFS4ERR_OP_ILLEGAL
);
goto
out
;
}
}
dprintk
(
"%s: minorversion=%d nop=%d op_nr=%u
\n
"
,
__func__
,
minorversion
,
nop
,
op_nr
);
status
=
minorversion
?
preprocess_nfs41_op
(
nop
,
op_nr
,
&
op
)
:
preprocess_nfs4_op
(
op_nr
,
&
op
);
if
(
status
==
htonl
(
NFS4ERR_OP_ILLEGAL
))
op_nr
=
OP_CB_ILLEGAL
;
out:
maxlen
=
xdr_out
->
end
-
xdr_out
->
p
;
if
(
maxlen
>
0
&&
maxlen
<
PAGE_SIZE
)
{
if
(
likely
(
status
==
0
&&
op
->
decode_args
!=
NULL
))
...
...
@@ -425,7 +652,8 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r
return
rpc_system_err
;
while
(
status
==
0
&&
nops
!=
hdr_arg
.
nops
)
{
status
=
process_op
(
rqstp
,
&
xdr_in
,
argp
,
&
xdr_out
,
resp
);
status
=
process_op
(
hdr_arg
.
minorversion
,
nops
,
rqstp
,
&
xdr_in
,
argp
,
&
xdr_out
,
resp
);
nops
++
;
}
...
...
@@ -452,7 +680,15 @@ static struct callback_op callback_ops[] = {
.
process_op
=
(
callback_process_op_t
)
nfs4_callback_recall
,
.
decode_args
=
(
callback_decode_arg_t
)
decode_recall_args
,
.
res_maxsize
=
CB_OP_RECALL_RES_MAXSZ
,
}
},
#if defined(CONFIG_NFS_V4_1)
[
OP_CB_SEQUENCE
]
=
{
.
process_op
=
(
callback_process_op_t
)
nfs4_callback_sequence
,
.
decode_args
=
(
callback_decode_arg_t
)
decode_cb_sequence_args
,
.
encode_res
=
(
callback_encode_res_t
)
encode_cb_sequence_res
,
.
res_maxsize
=
CB_OP_SEQUENCE_RES_MAXSZ
,
},
#endif
/* CONFIG_NFS_V4_1 */
};
/*
...
...
fs/nfs/client.c
View file @
301933a0
...
...
@@ -37,6 +37,7 @@
#include <linux/in6.h>
#include <net/ipv6.h>
#include <linux/nfs_xdr.h>
#include <linux/sunrpc/bc_xprt.h>
#include <asm/system.h>
...
...
@@ -102,6 +103,7 @@ struct nfs_client_initdata {
size_t
addrlen
;
const
struct
nfs_rpc_ops
*
rpc_ops
;
int
proto
;
u32
minorversion
;
};
/*
...
...
@@ -120,12 +122,6 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_
clp
->
rpc_ops
=
cl_init
->
rpc_ops
;
if
(
cl_init
->
rpc_ops
->
version
==
4
)
{
if
(
nfs_callback_up
()
<
0
)
goto
error_2
;
__set_bit
(
NFS_CS_CALLBACK
,
&
clp
->
cl_res_state
);
}
atomic_set
(
&
clp
->
cl_count
,
1
);
clp
->
cl_cons_state
=
NFS_CS_INITING
;
...
...
@@ -135,7 +131,7 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_
if
(
cl_init
->
hostname
)
{
clp
->
cl_hostname
=
kstrdup
(
cl_init
->
hostname
,
GFP_KERNEL
);
if
(
!
clp
->
cl_hostname
)
goto
error_
3
;
goto
error_
cleanup
;
}
INIT_LIST_HEAD
(
&
clp
->
cl_superblocks
);
...
...
@@ -150,6 +146,7 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_
rpc_init_wait_queue
(
&
clp
->
cl_rpcwaitq
,
"NFS client"
);
clp
->
cl_boot_time
=
CURRENT_TIME
;
clp
->
cl_state
=
1
<<
NFS4CLNT_LEASE_EXPIRED
;
clp
->
cl_minorversion
=
cl_init
->
minorversion
;
#endif
cred
=
rpc_lookup_machine_cred
();
if
(
!
IS_ERR
(
cred
))
...
...
@@ -159,10 +156,7 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_
return
clp
;
error_3:
if
(
__test_and_clear_bit
(
NFS_CS_CALLBACK
,
&
clp
->
cl_res_state
))
nfs_callback_down
();
error_2:
error_cleanup:
kfree
(
clp
);
error_0:
return
NULL
;
...
...
@@ -181,6 +175,35 @@ static void nfs4_shutdown_client(struct nfs_client *clp)
#endif
}
/*
* Destroy the NFS4 callback service
*/
static
void
nfs4_destroy_callback
(
struct
nfs_client
*
clp
)
{
#ifdef CONFIG_NFS_V4
if
(
__test_and_clear_bit
(
NFS_CS_CALLBACK
,
&
clp
->
cl_res_state
))
nfs_callback_down
(
clp
->
cl_minorversion
);
#endif
/* CONFIG_NFS_V4 */
}
/*
* Clears/puts all minor version specific parts from an nfs_client struct
* reverting it to minorversion 0.
*/
static
void
nfs4_clear_client_minor_version
(
struct
nfs_client
*
clp
)
{
#ifdef CONFIG_NFS_V4_1
if
(
nfs4_has_session
(
clp
))
{
nfs4_destroy_session
(
clp
->
cl_session
);
clp
->
cl_session
=
NULL
;
}
clp
->
cl_call_sync
=
_nfs4_call_sync
;
#endif
/* CONFIG_NFS_V4_1 */
nfs4_destroy_callback
(
clp
);
}
/*
* Destroy a shared client record
*/
...
...
@@ -188,6 +211,7 @@ static void nfs_free_client(struct nfs_client *clp)
{
dprintk
(
"--> nfs_free_client(%u)
\n
"
,
clp
->
rpc_ops
->
version
);
nfs4_clear_client_minor_version
(
clp
);
nfs4_shutdown_client
(
clp
);
nfs_fscache_release_client_cookie
(
clp
);
...
...
@@ -196,9 +220,6 @@ static void nfs_free_client(struct nfs_client *clp)
if
(
!
IS_ERR
(
clp
->
cl_rpcclient
))
rpc_shutdown_client
(
clp
->
cl_rpcclient
);
if
(
__test_and_clear_bit
(
NFS_CS_CALLBACK
,
&
clp
->
cl_res_state
))
nfs_callback_down
();
if
(
clp
->
cl_machine_cred
!=
NULL
)
put_rpccred
(
clp
->
cl_machine_cred
);
...
...
@@ -347,7 +368,8 @@ struct nfs_client *nfs_find_client(const struct sockaddr *addr, u32 nfsversion)
struct
sockaddr
*
clap
=
(
struct
sockaddr
*
)
&
clp
->
cl_addr
;
/* Don't match clients that failed to initialise properly */
if
(
clp
->
cl_cons_state
!=
NFS_CS_READY
)
if
(
!
(
clp
->
cl_cons_state
==
NFS_CS_READY
||
clp
->
cl_cons_state
==
NFS_CS_SESSION_INITING
))
continue
;
/* Different NFS versions cannot share the same nfs_client */
...
...
@@ -420,7 +442,9 @@ static struct nfs_client *nfs_match_client(const struct nfs_client_initdata *dat
if
(
clp
->
cl_proto
!=
data
->
proto
)
continue
;
/* Match nfsv4 minorversion */
if
(
clp
->
cl_minorversion
!=
data
->
minorversion
)
continue
;
/* Match the full socket address */
if
(
!
nfs_sockaddr_cmp
(
sap
,
clap
))
continue
;
...
...
@@ -478,7 +502,7 @@ static struct nfs_client *nfs_get_client(const struct nfs_client_initdata *cl_in
nfs_free_client
(
new
);
error
=
wait_event_killable
(
nfs_client_active_wq
,
clp
->
cl_cons_state
!=
NFS_CS_INITING
);
clp
->
cl_cons_state
<
NFS_CS_INITING
);
if
(
error
<
0
)
{
nfs_put_client
(
clp
);
return
ERR_PTR
(
-
ERESTARTSYS
);
...
...
@@ -499,12 +523,28 @@ static struct nfs_client *nfs_get_client(const struct nfs_client_initdata *cl_in
/*
* Mark a server as ready or failed
*/
static
void
nfs_mark_client_ready
(
struct
nfs_client
*
clp
,
int
state
)
void
nfs_mark_client_ready
(
struct
nfs_client
*
clp
,
int
state
)
{
clp
->
cl_cons_state
=
state
;
wake_up_all
(
&
nfs_client_active_wq
);
}
/*
* With sessions, the client is not marked ready until after a
* successful EXCHANGE_ID and CREATE_SESSION.
*
* Map errors cl_cons_state errors to EPROTONOSUPPORT to indicate
* other versions of NFS can be tried.
*/
int
nfs4_check_client_ready
(
struct
nfs_client
*
clp
)
{
if
(
!
nfs4_has_session
(
clp
))
return
0
;
if
(
clp
->
cl_cons_state
<
NFS_CS_READY
)
return
-
EPROTONOSUPPORT
;
return
0
;
}
/*
* Initialise the timeout values for a connection
*/
...
...
@@ -1049,6 +1089,61 @@ struct nfs_server *nfs_create_server(const struct nfs_parsed_mount_data *data,
}
#ifdef CONFIG_NFS_V4
/*
* Initialize the NFS4 callback service
*/
static
int
nfs4_init_callback
(
struct
nfs_client
*
clp
)
{
int
error
;
if
(
clp
->
rpc_ops
->
version
==
4
)
{
if
(
nfs4_has_session
(
clp
))
{
error
=
xprt_setup_backchannel
(
clp
->
cl_rpcclient
->
cl_xprt
,
NFS41_BC_MIN_CALLBACKS
);
if
(
error
<
0
)
return
error
;
}
error
=
nfs_callback_up
(
clp
->
cl_minorversion
,
clp
->
cl_rpcclient
->
cl_xprt
);
if
(
error
<
0
)
{
dprintk
(
"%s: failed to start callback. Error = %d
\n
"
,
__func__
,
error
);
return
error
;
}
__set_bit
(
NFS_CS_CALLBACK
,
&
clp
->
cl_res_state
);
}
return
0
;
}
/*
* Initialize the minor version specific parts of an NFS4 client record
*/
static
int
nfs4_init_client_minor_version
(
struct
nfs_client
*
clp
)
{
clp
->
cl_call_sync
=
_nfs4_call_sync
;
#if defined(CONFIG_NFS_V4_1)
if
(
clp
->
cl_minorversion
)
{
struct
nfs4_session
*
session
=
NULL
;
/*
* Create the session and mark it expired.
* When a SEQUENCE operation encounters the expired session
* it will do session recovery to initialize it.
*/
session
=
nfs4_alloc_session
(
clp
);
if
(
!
session
)
return
-
ENOMEM
;
clp
->
cl_session
=
session
;
clp
->
cl_call_sync
=
_nfs4_call_sync_session
;
}
#endif
/* CONFIG_NFS_V4_1 */
return
nfs4_init_callback
(
clp
);
}
/*
* Initialise an NFS4 client record
*/
...
...
@@ -1083,6 +1178,11 @@ static int nfs4_init_client(struct nfs_client *clp,
}
__set_bit
(
NFS_CS_IDMAP
,
&
clp
->
cl_res_state
);
error
=
nfs4_init_client_minor_version
(
clp
);
if
(
error
<
0
)
goto
error
;
if
(
!
nfs4_has_session
(
clp
))
nfs_mark_client_ready
(
clp
,
NFS_CS_READY
);
return
0
;
...
...
@@ -1101,7 +1201,8 @@ static int nfs4_set_client(struct nfs_server *server,
const
size_t
addrlen
,
const
char
*
ip_addr
,
rpc_authflavor_t
authflavour
,
int
proto
,
const
struct
rpc_timeout
*
timeparms
)
int
proto
,
const
struct
rpc_timeout
*
timeparms
,
u32
minorversion
)
{
struct
nfs_client_initdata
cl_init
=
{
.
hostname
=
hostname
,
...
...
@@ -1109,6 +1210,7 @@ static int nfs4_set_client(struct nfs_server *server,
.
addrlen
=
addrlen
,
.
rpc_ops
=
&
nfs_v4_clientops
,
.
proto
=
proto
,
.
minorversion
=
minorversion
,
};
struct
nfs_client
*
clp
;
int
error
;
...
...
@@ -1137,6 +1239,36 @@ static int nfs4_set_client(struct nfs_server *server,
return
error
;
}
/*
* Initialize a session.
* Note: save the mount rsize and wsize for create_server negotiation.
*/
static
void
nfs4_init_session
(
struct
nfs_client
*
clp
,
unsigned
int
wsize
,
unsigned
int
rsize
)
{
#if defined(CONFIG_NFS_V4_1)
if
(
nfs4_has_session
(
clp
))
{
clp
->
cl_session
->
fc_attrs
.
max_rqst_sz
=
wsize
;
clp
->
cl_session
->
fc_attrs
.
max_resp_sz
=
rsize
;
}
#endif
/* CONFIG_NFS_V4_1 */
}
/*
* Session has been established, and the client marked ready.
* Set the mount rsize and wsize with negotiated fore channel
* attributes which will be bound checked in nfs_server_set_fsinfo.
*/
static
void
nfs4_session_set_rwsize
(
struct
nfs_server
*
server
)
{
#ifdef CONFIG_NFS_V4_1
if
(
!
nfs4_has_session
(
server
->
nfs_client
))
return
;
server
->
rsize
=
server
->
nfs_client
->
cl_session
->
fc_attrs
.
max_resp_sz
;
server
->
wsize
=
server
->
nfs_client
->
cl_session
->
fc_attrs
.
max_rqst_sz
;
#endif
/* CONFIG_NFS_V4_1 */
}
/*
* Create a version 4 volume record
*/
...
...
@@ -1164,7 +1296,8 @@ static int nfs4_init_server(struct nfs_server *server,
data
->
client_address
,
data
->
auth_flavors
[
0
],
data
->
nfs_server
.
protocol
,
&
timeparms
);
&
timeparms
,
data
->
minorversion
);
if
(
error
<
0
)
goto
error
;
...
...
@@ -1214,6 +1347,8 @@ struct nfs_server *nfs4_create_server(const struct nfs_parsed_mount_data *data,
BUG_ON
(
!
server
->
nfs_client
->
rpc_ops
);
BUG_ON
(
!
server
->
nfs_client
->
rpc_ops
->
file_inode_ops
);
nfs4_init_session
(
server
->
nfs_client
,
server
->
wsize
,
server
->
rsize
);
/* Probe the root fh to retrieve its FSID */
error
=
nfs4_path_walk
(
server
,
mntfh
,
data
->
nfs_server
.
export_path
);
if
(
error
<
0
)
...
...
@@ -1224,6 +1359,8 @@ struct nfs_server *nfs4_create_server(const struct nfs_parsed_mount_data *data,
(
unsigned
long
long
)
server
->
fsid
.
minor
);
dprintk
(
"Mount FH: %d
\n
"
,
mntfh
->
size
);
nfs4_session_set_rwsize
(
server
);
error
=
nfs_probe_fsinfo
(
server
,
mntfh
,
&
fattr
);
if
(
error
<
0
)
goto
error
;
...
...
@@ -1282,7 +1419,8 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data,
parent_client
->
cl_ipaddr
,
data
->
authflavor
,
parent_server
->
client
->
cl_xprt
->
prot
,
parent_server
->
client
->
cl_timeout
);
parent_server
->
client
->
cl_timeout
,
parent_client
->
cl_minorversion
);
if
(
error
<
0
)
goto
error
;
...
...
fs/nfs/direct.c
View file @
301933a0
...
...
@@ -259,6 +259,9 @@ static void nfs_direct_read_release(void *calldata)
}
static
const
struct
rpc_call_ops
nfs_read_direct_ops
=
{
#if defined(CONFIG_NFS_V4_1)
.
rpc_call_prepare
=
nfs_read_prepare
,
#endif
/* CONFIG_NFS_V4_1 */
.
rpc_call_done
=
nfs_direct_read_result
,
.
rpc_release
=
nfs_direct_read_release
,
};
...
...
@@ -535,6 +538,9 @@ static void nfs_direct_commit_release(void *calldata)
}
static
const
struct
rpc_call_ops
nfs_commit_direct_ops
=
{
#if defined(CONFIG_NFS_V4_1)
.
rpc_call_prepare
=
nfs_write_prepare
,
#endif
/* CONFIG_NFS_V4_1 */
.
rpc_call_done
=
nfs_direct_commit_result
,
.
rpc_release
=
nfs_direct_commit_release
,
};
...
...
@@ -673,6 +679,9 @@ static void nfs_direct_write_release(void *calldata)
}
static
const
struct
rpc_call_ops
nfs_write_direct_ops
=
{
#if defined(CONFIG_NFS_V4_1)
.
rpc_call_prepare
=
nfs_write_prepare
,
#endif
/* CONFIG_NFS_V4_1 */
.
rpc_call_done
=
nfs_direct_write_result
,
.
rpc_release
=
nfs_direct_write_release
,
};
...
...
fs/nfs/internal.h
View file @
301933a0
...
...
@@ -2,6 +2,7 @@
* NFS internal definitions
*/
#include "nfs4_fs.h"
#include <linux/mount.h>
#include <linux/security.h>
...
...
@@ -17,6 +18,18 @@ struct nfs_string;
*/
#define NFS_MAX_READAHEAD (RPC_DEF_SLOT_TABLE - 1)
/*
* Determine if sessions are in use.
*/
static
inline
int
nfs4_has_session
(
const
struct
nfs_client
*
clp
)
{
#ifdef CONFIG_NFS_V4_1
if
(
clp
->
cl_session
)
return
1
;
#endif
/* CONFIG_NFS_V4_1 */
return
0
;
}
struct
nfs_clone_mount
{
const
struct
super_block
*
sb
;
const
struct
dentry
*
dentry
;
...
...
@@ -44,6 +57,7 @@ struct nfs_parsed_mount_data {
unsigned
int
auth_flavor_len
;
rpc_authflavor_t
auth_flavors
[
1
];
char
*
client_address
;
unsigned
int
minorversion
;
char
*
fscache_uniq
;
struct
{
...
...
@@ -99,6 +113,8 @@ extern void nfs_free_server(struct nfs_server *server);
extern
struct
nfs_server
*
nfs_clone_server
(
struct
nfs_server
*
,
struct
nfs_fh
*
,
struct
nfs_fattr
*
);
extern
void
nfs_mark_client_ready
(
struct
nfs_client
*
clp
,
int
state
);
extern
int
nfs4_check_client_ready
(
struct
nfs_client
*
clp
);
#ifdef CONFIG_PROC_FS
extern
int
__init
nfs_fs_proc_init
(
void
);
extern
void
nfs_fs_proc_exit
(
void
);
...
...
@@ -146,6 +162,20 @@ extern __be32 * nfs_decode_dirent(__be32 *, struct nfs_entry *, int);
extern
struct
rpc_procinfo
nfs3_procedures
[];
extern
__be32
*
nfs3_decode_dirent
(
__be32
*
,
struct
nfs_entry
*
,
int
);
/* nfs4proc.c */
static
inline
void
nfs4_restart_rpc
(
struct
rpc_task
*
task
,
const
struct
nfs_client
*
clp
)
{
#ifdef CONFIG_NFS_V4_1
if
(
nfs4_has_session
(
clp
)
&&
test_bit
(
NFS4CLNT_SESSION_SETUP
,
&
clp
->
cl_state
))
{
rpc_restart_call_prepare
(
task
);
return
;
}
#endif
/* CONFIG_NFS_V4_1 */
rpc_restart_call
(
task
);
}
/* nfs4xdr.c */
#ifdef CONFIG_NFS_V4
extern
__be32
*
nfs4_decode_dirent
(
__be32
*
p
,
struct
nfs_entry
*
entry
,
int
plus
);
...
...
@@ -205,6 +235,38 @@ extern int nfs4_path_walk(struct nfs_server *server,
const
char
*
path
);
#endif
/* read.c */
extern
void
nfs_read_prepare
(
struct
rpc_task
*
task
,
void
*
calldata
);
/* write.c */
extern
void
nfs_write_prepare
(
struct
rpc_task
*
task
,
void
*
calldata
);
/* nfs4proc.c */
extern
int
_nfs4_call_sync
(
struct
nfs_server
*
server
,
struct
rpc_message
*
msg
,
struct
nfs4_sequence_args
*
args
,
struct
nfs4_sequence_res
*
res
,
int
cache_reply
);
extern
int
_nfs4_call_sync_session
(
struct
nfs_server
*
server
,
struct
rpc_message
*
msg
,
struct
nfs4_sequence_args
*
args
,
struct
nfs4_sequence_res
*
res
,
int
cache_reply
);
#ifdef CONFIG_NFS_V4_1
extern
void
nfs41_sequence_free_slot
(
const
struct
nfs_client
*
,
struct
nfs4_sequence_res
*
res
);
#endif
/* CONFIG_NFS_V4_1 */
static
inline
void
nfs4_sequence_free_slot
(
const
struct
nfs_client
*
clp
,
struct
nfs4_sequence_res
*
res
)
{
#ifdef CONFIG_NFS_V4_1
if
(
nfs4_has_session
(
clp
))
nfs41_sequence_free_slot
(
clp
,
res
);
#endif
/* CONFIG_NFS_V4_1 */
}
/*
* Determine the device name as a string
*/
...
...
fs/nfs/nfs4_fs.h
View file @
301933a0
...
...
@@ -44,6 +44,7 @@ enum nfs4_client_state {
NFS4CLNT_RECLAIM_REBOOT
,
NFS4CLNT_RECLAIM_NOGRACE
,
NFS4CLNT_DELEGRETURN
,
NFS4CLNT_SESSION_SETUP
,
};
/*
...
...
@@ -177,6 +178,14 @@ struct nfs4_state_recovery_ops {
int
state_flag_bit
;
int
(
*
recover_open
)(
struct
nfs4_state_owner
*
,
struct
nfs4_state
*
);
int
(
*
recover_lock
)(
struct
nfs4_state
*
,
struct
file_lock
*
);
int
(
*
establish_clid
)(
struct
nfs_client
*
,
struct
rpc_cred
*
);
struct
rpc_cred
*
(
*
get_clid_cred
)(
struct
nfs_client
*
);
};
struct
nfs4_state_maintenance_ops
{
int
(
*
sched_state_renewal
)(
struct
nfs_client
*
,
struct
rpc_cred
*
);
struct
rpc_cred
*
(
*
get_state_renewal_cred_locked
)(
struct
nfs_client
*
);
int
(
*
renew_lease
)(
struct
nfs_client
*
,
struct
rpc_cred
*
);
};
extern
const
struct
dentry_operations
nfs4_dentry_operations
;
...
...
@@ -193,6 +202,7 @@ extern int nfs4_proc_setclientid(struct nfs_client *, u32, unsigned short, struc
extern
int
nfs4_proc_setclientid_confirm
(
struct
nfs_client
*
,
struct
rpc_cred
*
);
extern
int
nfs4_proc_async_renew
(
struct
nfs_client
*
,
struct
rpc_cred
*
);
extern
int
nfs4_proc_renew
(
struct
nfs_client
*
,
struct
rpc_cred
*
);
extern
int
nfs4_init_clientid
(
struct
nfs_client
*
,
struct
rpc_cred
*
);
extern
int
nfs4_do_close
(
struct
path
*
path
,
struct
nfs4_state
*
state
,
int
wait
);
extern
struct
dentry
*
nfs4_atomic_open
(
struct
inode
*
,
struct
dentry
*
,
struct
nameidata
*
);
extern
int
nfs4_open_revalidate
(
struct
inode
*
,
struct
dentry
*
,
int
,
struct
nameidata
*
);
...
...
@@ -200,8 +210,26 @@ extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fh
extern
int
nfs4_proc_fs_locations
(
struct
inode
*
dir
,
const
struct
qstr
*
name
,
struct
nfs4_fs_locations
*
fs_locations
,
struct
page
*
page
);
extern
struct
nfs4_state_recovery_ops
nfs4_reboot_recovery_ops
;
extern
struct
nfs4_state_recovery_ops
nfs4_nograce_recovery_ops
;
extern
struct
nfs4_state_recovery_ops
*
nfs4_reboot_recovery_ops
[];
extern
struct
nfs4_state_recovery_ops
*
nfs4_nograce_recovery_ops
[];
#if defined(CONFIG_NFS_V4_1)
extern
int
nfs4_setup_sequence
(
struct
nfs_client
*
clp
,
struct
nfs4_sequence_args
*
args
,
struct
nfs4_sequence_res
*
res
,
int
cache_reply
,
struct
rpc_task
*
task
);
extern
void
nfs4_destroy_session
(
struct
nfs4_session
*
session
);
extern
struct
nfs4_session
*
nfs4_alloc_session
(
struct
nfs_client
*
clp
);
extern
int
nfs4_proc_create_session
(
struct
nfs_client
*
,
int
reset
);
extern
int
nfs4_proc_destroy_session
(
struct
nfs4_session
*
);
#else
/* CONFIG_NFS_v4_1 */
static
inline
int
nfs4_setup_sequence
(
struct
nfs_client
*
clp
,
struct
nfs4_sequence_args
*
args
,
struct
nfs4_sequence_res
*
res
,
int
cache_reply
,
struct
rpc_task
*
task
)
{
return
0
;
}
#endif
/* CONFIG_NFS_V4_1 */
extern
struct
nfs4_state_maintenance_ops
*
nfs4_state_renewal_ops
[];
extern
const
u32
nfs4_fattr_bitmap
[
2
];
extern
const
u32
nfs4_statfs_bitmap
[
2
];
...
...
@@ -216,7 +244,12 @@ extern void nfs4_kill_renewd(struct nfs_client *);
extern
void
nfs4_renew_state
(
struct
work_struct
*
);
/* nfs4state.c */
struct
rpc_cred
*
nfs4_get_setclientid_cred
(
struct
nfs_client
*
clp
);
struct
rpc_cred
*
nfs4_get_renew_cred_locked
(
struct
nfs_client
*
clp
);
#if defined(CONFIG_NFS_V4_1)
struct
rpc_cred
*
nfs4_get_machine_cred_locked
(
struct
nfs_client
*
clp
);
struct
rpc_cred
*
nfs4_get_exchange_id_cred
(
struct
nfs_client
*
clp
);
#endif
/* CONFIG_NFS_V4_1 */
extern
struct
nfs4_state_owner
*
nfs4_get_state_owner
(
struct
nfs_server
*
,
struct
rpc_cred
*
);
extern
void
nfs4_put_state_owner
(
struct
nfs4_state_owner
*
);
...
...
fs/nfs/nfs4proc.c
View file @
301933a0
...
...
@@ -48,11 +48,14 @@
#include <linux/smp_lock.h>
#include <linux/namei.h>
#include <linux/mount.h>
#include <linux/module.h>
#include <linux/sunrpc/bc_xprt.h>
#include "nfs4_fs.h"
#include "delegation.h"
#include "internal.h"
#include "iostat.h"
#include "callback.h"
#define NFSDBG_FACILITY NFSDBG_PROC
...
...
@@ -247,7 +250,25 @@ static int nfs4_handle_exception(const struct nfs_server *server, int errorcode,
ret
=
nfs4_wait_clnt_recover
(
clp
);
if
(
ret
==
0
)
exception
->
retry
=
1
;
#if !defined(CONFIG_NFS_V4_1)
break
;
#else
/* !defined(CONFIG_NFS_V4_1) */
if
(
!
nfs4_has_session
(
server
->
nfs_client
))
break
;
/* FALLTHROUGH */
case
-
NFS4ERR_BADSESSION
:
case
-
NFS4ERR_BADSLOT
:
case
-
NFS4ERR_BAD_HIGH_SLOT
:
case
-
NFS4ERR_CONN_NOT_BOUND_TO_SESSION
:
case
-
NFS4ERR_DEADSESSION
:
case
-
NFS4ERR_SEQ_FALSE_RETRY
:
case
-
NFS4ERR_SEQ_MISORDERED
:
dprintk
(
"%s ERROR: %d Reset session
\n
"
,
__func__
,
errorcode
);
set_bit
(
NFS4CLNT_SESSION_SETUP
,
&
clp
->
cl_state
);
exception
->
retry
=
1
;
/* FALLTHROUGH */
#endif
/* !defined(CONFIG_NFS_V4_1) */
case
-
NFS4ERR_FILE_OPEN
:
case
-
NFS4ERR_GRACE
:
case
-
NFS4ERR_DELAY
:
...
...
@@ -271,6 +292,353 @@ static void renew_lease(const struct nfs_server *server, unsigned long timestamp
spin_unlock
(
&
clp
->
cl_lock
);
}
#if defined(CONFIG_NFS_V4_1)
/*
* nfs4_free_slot - free a slot and efficiently update slot table.
*
* freeing a slot is trivially done by clearing its respective bit
* in the bitmap.
* If the freed slotid equals highest_used_slotid we want to update it
* so that the server would be able to size down the slot table if needed,
* otherwise we know that the highest_used_slotid is still in use.
* When updating highest_used_slotid there may be "holes" in the bitmap
* so we need to scan down from highest_used_slotid to 0 looking for the now
* highest slotid in use.
* If none found, highest_used_slotid is set to -1.
*/
static
void
nfs4_free_slot
(
struct
nfs4_slot_table
*
tbl
,
u8
free_slotid
)
{
int
slotid
=
free_slotid
;
spin_lock
(
&
tbl
->
slot_tbl_lock
);
/* clear used bit in bitmap */
__clear_bit
(
slotid
,
tbl
->
used_slots
);
/* update highest_used_slotid when it is freed */
if
(
slotid
==
tbl
->
highest_used_slotid
)
{
slotid
=
find_last_bit
(
tbl
->
used_slots
,
tbl
->
max_slots
);
if
(
slotid
>=
0
&&
slotid
<
tbl
->
max_slots
)
tbl
->
highest_used_slotid
=
slotid
;
else
tbl
->
highest_used_slotid
=
-
1
;
}
rpc_wake_up_next
(
&
tbl
->
slot_tbl_waitq
);
spin_unlock
(
&
tbl
->
slot_tbl_lock
);
dprintk
(
"%s: free_slotid %u highest_used_slotid %d
\n
"
,
__func__
,
free_slotid
,
tbl
->
highest_used_slotid
);
}
void
nfs41_sequence_free_slot
(
const
struct
nfs_client
*
clp
,
struct
nfs4_sequence_res
*
res
)
{
struct
nfs4_slot_table
*
tbl
;
if
(
!
nfs4_has_session
(
clp
))
{
dprintk
(
"%s: No session
\n
"
,
__func__
);
return
;
}
tbl
=
&
clp
->
cl_session
->
fc_slot_table
;
if
(
res
->
sr_slotid
==
NFS4_MAX_SLOT_TABLE
)
{
dprintk
(
"%s: No slot
\n
"
,
__func__
);
/* just wake up the next guy waiting since
* we may have not consumed a slot after all */
rpc_wake_up_next
(
&
tbl
->
slot_tbl_waitq
);
return
;
}
nfs4_free_slot
(
tbl
,
res
->
sr_slotid
);
res
->
sr_slotid
=
NFS4_MAX_SLOT_TABLE
;
}
static
void
nfs41_sequence_done
(
struct
nfs_client
*
clp
,
struct
nfs4_sequence_res
*
res
,
int
rpc_status
)
{
unsigned
long
timestamp
;
struct
nfs4_slot_table
*
tbl
;
struct
nfs4_slot
*
slot
;
/*
* sr_status remains 1 if an RPC level error occurred. The server
* may or may not have processed the sequence operation..
* Proceed as if the server received and processed the sequence
* operation.
*/
if
(
res
->
sr_status
==
1
)
res
->
sr_status
=
NFS_OK
;
/* -ERESTARTSYS can result in skipping nfs41_sequence_setup */
if
(
res
->
sr_slotid
==
NFS4_MAX_SLOT_TABLE
)
goto
out
;
tbl
=
&
clp
->
cl_session
->
fc_slot_table
;
slot
=
tbl
->
slots
+
res
->
sr_slotid
;
if
(
res
->
sr_status
==
0
)
{
/* Update the slot's sequence and clientid lease timer */
++
slot
->
seq_nr
;
timestamp
=
res
->
sr_renewal_time
;
spin_lock
(
&
clp
->
cl_lock
);
if
(
time_before
(
clp
->
cl_last_renewal
,
timestamp
))
clp
->
cl_last_renewal
=
timestamp
;
spin_unlock
(
&
clp
->
cl_lock
);
return
;
}
out:
/* The session may be reset by one of the error handlers. */
dprintk
(
"%s: Error %d free the slot
\n
"
,
__func__
,
res
->
sr_status
);
nfs41_sequence_free_slot
(
clp
,
res
);
}
/*
* nfs4_find_slot - efficiently look for a free slot
*
* nfs4_find_slot looks for an unset bit in the used_slots bitmap.
* If found, we mark the slot as used, update the highest_used_slotid,
* and respectively set up the sequence operation args.
* The slot number is returned if found, or NFS4_MAX_SLOT_TABLE otherwise.
*
* Note: must be called with under the slot_tbl_lock.
*/
static
u8
nfs4_find_slot
(
struct
nfs4_slot_table
*
tbl
,
struct
rpc_task
*
task
)
{
int
slotid
;
u8
ret_id
=
NFS4_MAX_SLOT_TABLE
;
BUILD_BUG_ON
((
u8
)
NFS4_MAX_SLOT_TABLE
!=
(
int
)
NFS4_MAX_SLOT_TABLE
);
dprintk
(
"--> %s used_slots=%04lx highest_used=%d max_slots=%d
\n
"
,
__func__
,
tbl
->
used_slots
[
0
],
tbl
->
highest_used_slotid
,
tbl
->
max_slots
);
slotid
=
find_first_zero_bit
(
tbl
->
used_slots
,
tbl
->
max_slots
);
if
(
slotid
>=
tbl
->
max_slots
)
goto
out
;
__set_bit
(
slotid
,
tbl
->
used_slots
);
if
(
slotid
>
tbl
->
highest_used_slotid
)
tbl
->
highest_used_slotid
=
slotid
;
ret_id
=
slotid
;
out:
dprintk
(
"<-- %s used_slots=%04lx highest_used=%d slotid=%d
\n
"
,
__func__
,
tbl
->
used_slots
[
0
],
tbl
->
highest_used_slotid
,
ret_id
);
return
ret_id
;
}
static
int
nfs4_recover_session
(
struct
nfs4_session
*
session
)
{
struct
nfs_client
*
clp
=
session
->
clp
;
int
ret
;
for
(;;)
{
ret
=
nfs4_wait_clnt_recover
(
clp
);
if
(
ret
!=
0
)
return
ret
;
if
(
!
test_bit
(
NFS4CLNT_SESSION_SETUP
,
&
clp
->
cl_state
))
break
;
nfs4_schedule_state_manager
(
clp
);
}
return
0
;
}
static
int
nfs41_setup_sequence
(
struct
nfs4_session
*
session
,
struct
nfs4_sequence_args
*
args
,
struct
nfs4_sequence_res
*
res
,
int
cache_reply
,
struct
rpc_task
*
task
)
{
struct
nfs4_slot
*
slot
;
struct
nfs4_slot_table
*
tbl
;
int
status
=
0
;
u8
slotid
;
dprintk
(
"--> %s
\n
"
,
__func__
);
/* slot already allocated? */
if
(
res
->
sr_slotid
!=
NFS4_MAX_SLOT_TABLE
)
return
0
;
memset
(
res
,
0
,
sizeof
(
*
res
));
res
->
sr_slotid
=
NFS4_MAX_SLOT_TABLE
;
tbl
=
&
session
->
fc_slot_table
;
spin_lock
(
&
tbl
->
slot_tbl_lock
);
if
(
test_bit
(
NFS4CLNT_SESSION_SETUP
,
&
session
->
clp
->
cl_state
))
{
if
(
tbl
->
highest_used_slotid
!=
-
1
)
{
rpc_sleep_on
(
&
tbl
->
slot_tbl_waitq
,
task
,
NULL
);
spin_unlock
(
&
tbl
->
slot_tbl_lock
);
dprintk
(
"<-- %s: Session reset: draining
\n
"
,
__func__
);
return
-
EAGAIN
;
}
/* The slot table is empty; start the reset thread */
dprintk
(
"%s Session Reset
\n
"
,
__func__
);
spin_unlock
(
&
tbl
->
slot_tbl_lock
);
status
=
nfs4_recover_session
(
session
);
if
(
status
)
return
status
;
spin_lock
(
&
tbl
->
slot_tbl_lock
);
}
slotid
=
nfs4_find_slot
(
tbl
,
task
);
if
(
slotid
==
NFS4_MAX_SLOT_TABLE
)
{
rpc_sleep_on
(
&
tbl
->
slot_tbl_waitq
,
task
,
NULL
);
spin_unlock
(
&
tbl
->
slot_tbl_lock
);
dprintk
(
"<-- %s: no free slots
\n
"
,
__func__
);
return
-
EAGAIN
;
}
spin_unlock
(
&
tbl
->
slot_tbl_lock
);
slot
=
tbl
->
slots
+
slotid
;
args
->
sa_session
=
session
;
args
->
sa_slotid
=
slotid
;
args
->
sa_cache_this
=
cache_reply
;
dprintk
(
"<-- %s slotid=%d seqid=%d
\n
"
,
__func__
,
slotid
,
slot
->
seq_nr
);
res
->
sr_session
=
session
;
res
->
sr_slotid
=
slotid
;
res
->
sr_renewal_time
=
jiffies
;
/*
* sr_status is only set in decode_sequence, and so will remain
* set to 1 if an rpc level failure occurs.
*/
res
->
sr_status
=
1
;
return
0
;
}
int
nfs4_setup_sequence
(
struct
nfs_client
*
clp
,
struct
nfs4_sequence_args
*
args
,
struct
nfs4_sequence_res
*
res
,
int
cache_reply
,
struct
rpc_task
*
task
)
{
int
ret
=
0
;
dprintk
(
"--> %s clp %p session %p sr_slotid %d
\n
"
,
__func__
,
clp
,
clp
->
cl_session
,
res
->
sr_slotid
);
if
(
!
nfs4_has_session
(
clp
))
goto
out
;
ret
=
nfs41_setup_sequence
(
clp
->
cl_session
,
args
,
res
,
cache_reply
,
task
);
if
(
ret
!=
-
EAGAIN
)
{
/* terminate rpc task */
task
->
tk_status
=
ret
;
task
->
tk_action
=
NULL
;
}
out:
dprintk
(
"<-- %s status=%d
\n
"
,
__func__
,
ret
);
return
ret
;
}
struct
nfs41_call_sync_data
{
struct
nfs_client
*
clp
;
struct
nfs4_sequence_args
*
seq_args
;
struct
nfs4_sequence_res
*
seq_res
;
int
cache_reply
;
};
static
void
nfs41_call_sync_prepare
(
struct
rpc_task
*
task
,
void
*
calldata
)
{
struct
nfs41_call_sync_data
*
data
=
calldata
;
dprintk
(
"--> %s data->clp->cl_session %p
\n
"
,
__func__
,
data
->
clp
->
cl_session
);
if
(
nfs4_setup_sequence
(
data
->
clp
,
data
->
seq_args
,
data
->
seq_res
,
data
->
cache_reply
,
task
))
return
;
rpc_call_start
(
task
);
}
static
void
nfs41_call_sync_done
(
struct
rpc_task
*
task
,
void
*
calldata
)
{
struct
nfs41_call_sync_data
*
data
=
calldata
;
nfs41_sequence_done
(
data
->
clp
,
data
->
seq_res
,
task
->
tk_status
);
nfs41_sequence_free_slot
(
data
->
clp
,
data
->
seq_res
);
}
struct
rpc_call_ops
nfs41_call_sync_ops
=
{
.
rpc_call_prepare
=
nfs41_call_sync_prepare
,
.
rpc_call_done
=
nfs41_call_sync_done
,
};
static
int
nfs4_call_sync_sequence
(
struct
nfs_client
*
clp
,
struct
rpc_clnt
*
clnt
,
struct
rpc_message
*
msg
,
struct
nfs4_sequence_args
*
args
,
struct
nfs4_sequence_res
*
res
,
int
cache_reply
)
{
int
ret
;
struct
rpc_task
*
task
;
struct
nfs41_call_sync_data
data
=
{
.
clp
=
clp
,
.
seq_args
=
args
,
.
seq_res
=
res
,
.
cache_reply
=
cache_reply
,
};
struct
rpc_task_setup
task_setup
=
{
.
rpc_client
=
clnt
,
.
rpc_message
=
msg
,
.
callback_ops
=
&
nfs41_call_sync_ops
,
.
callback_data
=
&
data
};
res
->
sr_slotid
=
NFS4_MAX_SLOT_TABLE
;
task
=
rpc_run_task
(
&
task_setup
);
if
(
IS_ERR
(
task
))
ret
=
PTR_ERR
(
task
);
else
{
ret
=
task
->
tk_status
;
rpc_put_task
(
task
);
}
return
ret
;
}
int
_nfs4_call_sync_session
(
struct
nfs_server
*
server
,
struct
rpc_message
*
msg
,
struct
nfs4_sequence_args
*
args
,
struct
nfs4_sequence_res
*
res
,
int
cache_reply
)
{
return
nfs4_call_sync_sequence
(
server
->
nfs_client
,
server
->
client
,
msg
,
args
,
res
,
cache_reply
);
}
#endif
/* CONFIG_NFS_V4_1 */
int
_nfs4_call_sync
(
struct
nfs_server
*
server
,
struct
rpc_message
*
msg
,
struct
nfs4_sequence_args
*
args
,
struct
nfs4_sequence_res
*
res
,
int
cache_reply
)
{
args
->
sa_session
=
res
->
sr_session
=
NULL
;
return
rpc_call_sync
(
server
->
client
,
msg
,
0
);
}
#define nfs4_call_sync(server, msg, args, res, cache_reply) \
(server)->nfs_client->cl_call_sync((server), (msg), &(args)->seq_args, \
&(res)->seq_res, (cache_reply))
static
void
nfs4_sequence_done
(
const
struct
nfs_server
*
server
,
struct
nfs4_sequence_res
*
res
,
int
rpc_status
)
{
#ifdef CONFIG_NFS_V4_1
if
(
nfs4_has_session
(
server
->
nfs_client
))
nfs41_sequence_done
(
server
->
nfs_client
,
res
,
rpc_status
);
#endif
/* CONFIG_NFS_V4_1 */
}
/* no restart, therefore free slot here */
static
void
nfs4_sequence_done_free_slot
(
const
struct
nfs_server
*
server
,
struct
nfs4_sequence_res
*
res
,
int
rpc_status
)
{
nfs4_sequence_done
(
server
,
res
,
rpc_status
);
nfs4_sequence_free_slot
(
server
->
nfs_client
,
res
);
}
static
void
update_changeattr
(
struct
inode
*
dir
,
struct
nfs4_change_info
*
cinfo
)
{
struct
nfs_inode
*
nfsi
=
NFS_I
(
dir
);
...
...
@@ -343,6 +711,7 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path,
p
->
o_arg
.
server
=
server
;
p
->
o_arg
.
bitmask
=
server
->
attr_bitmask
;
p
->
o_arg
.
claim
=
NFS4_OPEN_CLAIM_NULL
;
p
->
o_res
.
seq_res
.
sr_slotid
=
NFS4_MAX_SLOT_TABLE
;
if
(
flags
&
O_EXCL
)
{
u32
*
s
=
(
u32
*
)
p
->
o_arg
.
u
.
verifier
.
data
;
s
[
0
]
=
jiffies
;
...
...
@@ -929,6 +1298,10 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata)
nfs_copy_fh
(
&
data
->
o_res
.
fh
,
data
->
o_arg
.
fh
);
}
data
->
timestamp
=
jiffies
;
if
(
nfs4_setup_sequence
(
data
->
o_arg
.
server
->
nfs_client
,
&
data
->
o_arg
.
seq_args
,
&
data
->
o_res
.
seq_res
,
1
,
task
))
return
;
rpc_call_start
(
task
);
return
;
out_no_action:
...
...
@@ -941,6 +1314,10 @@ static void nfs4_open_done(struct rpc_task *task, void *calldata)
struct
nfs4_opendata
*
data
=
calldata
;
data
->
rpc_status
=
task
->
tk_status
;
nfs4_sequence_done_free_slot
(
data
->
o_arg
.
server
,
&
data
->
o_res
.
seq_res
,
task
->
tk_status
);
if
(
RPC_ASSASSINATED
(
task
))
return
;
if
(
task
->
tk_status
==
0
)
{
...
...
@@ -1269,7 +1646,7 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
}
else
memcpy
(
&
arg
.
stateid
,
&
zero_stateid
,
sizeof
(
arg
.
stateid
));
status
=
rpc_call_sync
(
server
->
client
,
&
msg
,
0
);
status
=
nfs4_call_sync
(
server
,
&
msg
,
&
arg
,
&
res
,
1
);
if
(
status
==
0
&&
state
!=
NULL
)
renew_lease
(
server
,
timestamp
);
return
status
;
...
...
@@ -1318,6 +1695,7 @@ static void nfs4_close_done(struct rpc_task *task, void *data)
struct
nfs4_state
*
state
=
calldata
->
state
;
struct
nfs_server
*
server
=
NFS_SERVER
(
calldata
->
inode
);
nfs4_sequence_done
(
server
,
&
calldata
->
res
.
seq_res
,
task
->
tk_status
);
if
(
RPC_ASSASSINATED
(
task
))
return
;
/* hmm. we are done with the inode, and in the process of freeing
...
...
@@ -1336,10 +1714,11 @@ static void nfs4_close_done(struct rpc_task *task, void *data)
break
;
default:
if
(
nfs4_async_handle_error
(
task
,
server
,
state
)
==
-
EAGAIN
)
{
rpc_restart_call
(
task
);
nfs4_restart_rpc
(
task
,
server
->
nfs_client
);
return
;
}
}
nfs4_sequence_free_slot
(
server
->
nfs_client
,
&
calldata
->
res
.
seq_res
);
nfs_refresh_inode
(
calldata
->
inode
,
calldata
->
res
.
fattr
);
}
...
...
@@ -1380,6 +1759,10 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
calldata
->
arg
.
fmode
=
FMODE_WRITE
;
}
calldata
->
timestamp
=
jiffies
;
if
(
nfs4_setup_sequence
((
NFS_SERVER
(
calldata
->
inode
))
->
nfs_client
,
&
calldata
->
arg
.
seq_args
,
&
calldata
->
res
.
seq_res
,
1
,
task
))
return
;
rpc_call_start
(
task
);
}
...
...
@@ -1419,13 +1802,15 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait)
};
int
status
=
-
ENOMEM
;
calldata
=
k
m
alloc
(
sizeof
(
*
calldata
),
GFP_KERNEL
);
calldata
=
k
z
alloc
(
sizeof
(
*
calldata
),
GFP_KERNEL
);
if
(
calldata
==
NULL
)
goto
out
;
calldata
->
inode
=
state
->
inode
;
calldata
->
state
=
state
;
calldata
->
arg
.
fh
=
NFS_FH
(
state
->
inode
);
calldata
->
arg
.
stateid
=
&
state
->
open_stateid
;
if
(
nfs4_has_session
(
server
->
nfs_client
))
memset
(
calldata
->
arg
.
stateid
->
data
,
0
,
4
);
/* clear seqid */
/* Serialization for the sequence id */
calldata
->
arg
.
seqid
=
nfs_alloc_seqid
(
&
state
->
owner
->
so_seqid
);
if
(
calldata
->
arg
.
seqid
==
NULL
)
...
...
@@ -1435,6 +1820,7 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait)
calldata
->
res
.
fattr
=
&
calldata
->
fattr
;
calldata
->
res
.
seqid
=
calldata
->
arg
.
seqid
;
calldata
->
res
.
server
=
server
;
calldata
->
res
.
seq_res
.
sr_slotid
=
NFS4_MAX_SLOT_TABLE
;
calldata
->
path
.
mnt
=
mntget
(
path
->
mnt
);
calldata
->
path
.
dentry
=
dget
(
path
->
dentry
);
...
...
@@ -1584,15 +1970,18 @@ void nfs4_close_context(struct nfs_open_context *ctx, int is_sync)
static
int
_nfs4_server_capabilities
(
struct
nfs_server
*
server
,
struct
nfs_fh
*
fhandle
)
{
struct
nfs4_server_caps_arg
args
=
{
.
fhandle
=
fhandle
,
};
struct
nfs4_server_caps_res
res
=
{};
struct
rpc_message
msg
=
{
.
rpc_proc
=
&
nfs4_procedures
[
NFSPROC4_CLNT_SERVER_CAPS
],
.
rpc_argp
=
fhandle
,
.
rpc_argp
=
&
args
,
.
rpc_resp
=
&
res
,
};
int
status
;
status
=
rpc_call_sync
(
server
->
client
,
&
msg
,
0
);
status
=
nfs4_call_sync
(
server
,
&
msg
,
&
args
,
&
res
,
0
);
if
(
status
==
0
)
{
memcpy
(
server
->
attr_bitmask
,
res
.
attr_bitmask
,
sizeof
(
server
->
attr_bitmask
));
if
(
res
.
attr_bitmask
[
0
]
&
FATTR4_WORD0_ACL
)
...
...
@@ -1606,6 +1995,7 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f
server
->
cache_consistency_bitmask
[
1
]
&=
FATTR4_WORD1_TIME_METADATA
|
FATTR4_WORD1_TIME_MODIFY
;
server
->
acl_bitmask
=
res
.
acl_bitmask
;
}
return
status
;
}
...
...
@@ -1637,8 +2027,15 @@ static int _nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle,
.
rpc_argp
=
&
args
,
.
rpc_resp
=
&
res
,
};
int
status
;
nfs_fattr_init
(
info
->
fattr
);
return
rpc_call_sync
(
server
->
client
,
&
msg
,
0
);
status
=
nfs4_recover_expired_lease
(
server
);
if
(
!
status
)
status
=
nfs4_check_client_ready
(
server
->
nfs_client
);
if
(
!
status
)
status
=
nfs4_call_sync
(
server
,
&
msg
,
&
args
,
&
res
,
0
);
return
status
;
}
static
int
nfs4_lookup_root
(
struct
nfs_server
*
server
,
struct
nfs_fh
*
fhandle
,
...
...
@@ -1728,7 +2125,7 @@ static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
};
nfs_fattr_init
(
fattr
);
return
rpc_call_sync
(
server
->
client
,
&
msg
,
0
);
return
nfs4_call_sync
(
server
,
&
msg
,
&
args
,
&
res
,
0
);
}
static
int
nfs4_proc_getattr
(
struct
nfs_server
*
server
,
struct
nfs_fh
*
fhandle
,
struct
nfs_fattr
*
fattr
)
...
...
@@ -1812,7 +2209,7 @@ static int _nfs4_proc_lookupfh(struct nfs_server *server, const struct nfs_fh *d
nfs_fattr_init
(
fattr
);
dprintk
(
"NFS call lookupfh %s
\n
"
,
name
->
name
);
status
=
rpc_call_sync
(
server
->
client
,
&
msg
,
0
);
status
=
nfs4_call_sync
(
server
,
&
msg
,
&
args
,
&
res
,
0
);
dprintk
(
"NFS reply lookupfh: %d
\n
"
,
status
);
return
status
;
}
...
...
@@ -1898,7 +2295,7 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry
args
.
access
|=
NFS4_ACCESS_EXECUTE
;
}
nfs_fattr_init
(
&
fattr
);
status
=
rpc_call_sync
(
NFS_CLIENT
(
inode
),
&
msg
,
0
);
status
=
nfs4_call_sync
(
server
,
&
msg
,
&
args
,
&
res
,
0
);
if
(
!
status
)
{
entry
->
mask
=
0
;
if
(
res
.
access
&
NFS4_ACCESS_READ
)
...
...
@@ -1957,13 +2354,14 @@ static int _nfs4_proc_readlink(struct inode *inode, struct page *page,
.
pglen
=
pglen
,
.
pages
=
&
page
,
};
struct
nfs4_readlink_res
res
;
struct
rpc_message
msg
=
{
.
rpc_proc
=
&
nfs4_procedures
[
NFSPROC4_CLNT_READLINK
],
.
rpc_argp
=
&
args
,
.
rpc_resp
=
NULL
,
.
rpc_resp
=
&
res
,
};
return
rpc_call_sync
(
NFS_CLIENT
(
inode
),
&
msg
,
0
);
return
nfs4_call_sync
(
NFS_SERVER
(
inode
),
&
msg
,
&
args
,
&
res
,
0
);
}
static
int
nfs4_proc_readlink
(
struct
inode
*
inode
,
struct
page
*
page
,
...
...
@@ -2057,7 +2455,7 @@ static int _nfs4_proc_remove(struct inode *dir, struct qstr *name)
int
status
;
nfs_fattr_init
(
&
res
.
dir_attr
);
status
=
rpc_call_sync
(
server
->
client
,
&
msg
,
0
);
status
=
nfs4_call_sync
(
server
,
&
msg
,
&
args
,
&
res
,
1
);
if
(
status
==
0
)
{
update_changeattr
(
dir
,
&
res
.
cinfo
);
nfs_post_op_update_inode
(
dir
,
&
res
.
dir_attr
);
...
...
@@ -2092,8 +2490,10 @@ static int nfs4_proc_unlink_done(struct rpc_task *task, struct inode *dir)
{
struct
nfs_removeres
*
res
=
task
->
tk_msg
.
rpc_resp
;
nfs4_sequence_done
(
res
->
server
,
&
res
->
seq_res
,
task
->
tk_status
);
if
(
nfs4_async_handle_error
(
task
,
res
->
server
,
NULL
)
==
-
EAGAIN
)
return
0
;
nfs4_sequence_free_slot
(
res
->
server
->
nfs_client
,
&
res
->
seq_res
);
update_changeattr
(
dir
,
&
res
->
cinfo
);
nfs_post_op_update_inode
(
dir
,
&
res
->
dir_attr
);
return
1
;
...
...
@@ -2125,7 +2525,7 @@ static int _nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name,
nfs_fattr_init
(
res
.
old_fattr
);
nfs_fattr_init
(
res
.
new_fattr
);
status
=
rpc_call_sync
(
server
->
client
,
&
msg
,
0
);
status
=
nfs4_call_sync
(
server
,
&
msg
,
&
arg
,
&
res
,
1
);
if
(
!
status
)
{
update_changeattr
(
old_dir
,
&
res
.
old_cinfo
);
...
...
@@ -2174,7 +2574,7 @@ static int _nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *
nfs_fattr_init
(
res
.
fattr
);
nfs_fattr_init
(
res
.
dir_attr
);
status
=
rpc_call_sync
(
server
->
client
,
&
msg
,
0
);
status
=
nfs4_call_sync
(
server
,
&
msg
,
&
arg
,
&
res
,
1
);
if
(
!
status
)
{
update_changeattr
(
dir
,
&
res
.
cinfo
);
nfs_post_op_update_inode
(
dir
,
res
.
dir_attr
);
...
...
@@ -2235,7 +2635,8 @@ static struct nfs4_createdata *nfs4_alloc_createdata(struct inode *dir,
static
int
nfs4_do_create
(
struct
inode
*
dir
,
struct
dentry
*
dentry
,
struct
nfs4_createdata
*
data
)
{
int
status
=
rpc_call_sync
(
NFS_CLIENT
(
dir
),
&
data
->
msg
,
0
);
int
status
=
nfs4_call_sync
(
NFS_SERVER
(
dir
),
&
data
->
msg
,
&
data
->
arg
,
&
data
->
res
,
1
);
if
(
status
==
0
)
{
update_changeattr
(
dir
,
&
data
->
res
.
dir_cinfo
);
nfs_post_op_update_inode
(
dir
,
data
->
res
.
dir_fattr
);
...
...
@@ -2344,7 +2745,7 @@ static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
(
unsigned
long
long
)
cookie
);
nfs4_setup_readdir
(
cookie
,
NFS_COOKIEVERF
(
dir
),
dentry
,
&
args
);
res
.
pgbase
=
args
.
pgbase
;
status
=
rpc_call_sync
(
NFS_CLIENT
(
dir
),
&
msg
,
0
);
status
=
nfs4_call_sync
(
NFS_SERVER
(
dir
),
&
msg
,
&
args
,
&
res
,
0
);
if
(
status
==
0
)
memcpy
(
NFS_COOKIEVERF
(
dir
),
res
.
verifier
.
data
,
NFS4_VERIFIER_SIZE
);
...
...
@@ -2422,14 +2823,17 @@ static int _nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle,
.
fh
=
fhandle
,
.
bitmask
=
server
->
attr_bitmask
,
};
struct
nfs4_statfs_res
res
=
{
.
fsstat
=
fsstat
,
};
struct
rpc_message
msg
=
{
.
rpc_proc
=
&
nfs4_procedures
[
NFSPROC4_CLNT_STATFS
],
.
rpc_argp
=
&
args
,
.
rpc_resp
=
fsstat
,
.
rpc_resp
=
&
res
,
};
nfs_fattr_init
(
fsstat
->
fattr
);
return
rpc_call_sync
(
server
->
client
,
&
msg
,
0
);
return
nfs4_call_sync
(
server
,
&
msg
,
&
args
,
&
res
,
0
);
}
static
int
nfs4_proc_statfs
(
struct
nfs_server
*
server
,
struct
nfs_fh
*
fhandle
,
struct
nfs_fsstat
*
fsstat
)
...
...
@@ -2451,13 +2855,16 @@ static int _nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle,
.
fh
=
fhandle
,
.
bitmask
=
server
->
attr_bitmask
,
};
struct
nfs4_fsinfo_res
res
=
{
.
fsinfo
=
fsinfo
,
};
struct
rpc_message
msg
=
{
.
rpc_proc
=
&
nfs4_procedures
[
NFSPROC4_CLNT_FSINFO
],
.
rpc_argp
=
&
args
,
.
rpc_resp
=
fsinfo
,
.
rpc_resp
=
&
res
,
};
return
rpc_call_sync
(
server
->
client
,
&
msg
,
0
);
return
nfs4_call_sync
(
server
,
&
msg
,
&
args
,
&
res
,
0
);
}
static
int
nfs4_do_fsinfo
(
struct
nfs_server
*
server
,
struct
nfs_fh
*
fhandle
,
struct
nfs_fsinfo
*
fsinfo
)
...
...
@@ -2486,10 +2893,13 @@ static int _nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle
.
fh
=
fhandle
,
.
bitmask
=
server
->
attr_bitmask
,
};
struct
nfs4_pathconf_res
res
=
{
.
pathconf
=
pathconf
,
};
struct
rpc_message
msg
=
{
.
rpc_proc
=
&
nfs4_procedures
[
NFSPROC4_CLNT_PATHCONF
],
.
rpc_argp
=
&
args
,
.
rpc_resp
=
pathconf
,
.
rpc_resp
=
&
res
,
};
/* None of the pathconf attributes are mandatory to implement */
...
...
@@ -2499,7 +2909,7 @@ static int _nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle
}
nfs_fattr_init
(
pathconf
->
fattr
);
return
rpc_call_sync
(
server
->
client
,
&
msg
,
0
);
return
nfs4_call_sync
(
server
,
&
msg
,
&
args
,
&
res
,
0
);
}
static
int
nfs4_proc_pathconf
(
struct
nfs_server
*
server
,
struct
nfs_fh
*
fhandle
,
...
...
@@ -2520,8 +2930,13 @@ static int nfs4_read_done(struct rpc_task *task, struct nfs_read_data *data)
{
struct
nfs_server
*
server
=
NFS_SERVER
(
data
->
inode
);
dprintk
(
"--> %s
\n
"
,
__func__
);
/* nfs4_sequence_free_slot called in the read rpc_call_done */
nfs4_sequence_done
(
server
,
&
data
->
res
.
seq_res
,
task
->
tk_status
);
if
(
nfs4_async_handle_error
(
task
,
server
,
data
->
args
.
context
->
state
)
==
-
EAGAIN
)
{
rpc_restart_call
(
task
);
nfs4_restart_rpc
(
task
,
server
->
nfs_client
);
return
-
EAGAIN
;
}
...
...
@@ -2541,8 +2956,12 @@ static int nfs4_write_done(struct rpc_task *task, struct nfs_write_data *data)
{
struct
inode
*
inode
=
data
->
inode
;
/* slot is freed in nfs_writeback_done */
nfs4_sequence_done
(
NFS_SERVER
(
inode
),
&
data
->
res
.
seq_res
,
task
->
tk_status
);
if
(
nfs4_async_handle_error
(
task
,
NFS_SERVER
(
inode
),
data
->
args
.
context
->
state
)
==
-
EAGAIN
)
{
rpc_restart_call
(
task
);
nfs4_restart_rpc
(
task
,
NFS_SERVER
(
inode
)
->
nfs_client
);
return
-
EAGAIN
;
}
if
(
task
->
tk_status
>=
0
)
{
...
...
@@ -2567,10 +2986,14 @@ static int nfs4_commit_done(struct rpc_task *task, struct nfs_write_data *data)
{
struct
inode
*
inode
=
data
->
inode
;
nfs4_sequence_done
(
NFS_SERVER
(
inode
),
&
data
->
res
.
seq_res
,
task
->
tk_status
);
if
(
nfs4_async_handle_error
(
task
,
NFS_SERVER
(
inode
),
NULL
)
==
-
EAGAIN
)
{
rpc_restart_call
(
task
);
nfs4_restart_rpc
(
task
,
NFS_SERVER
(
inode
)
->
nfs_client
);
return
-
EAGAIN
;
}
nfs4_sequence_free_slot
(
NFS_SERVER
(
inode
)
->
nfs_client
,
&
data
->
res
.
seq_res
);
nfs_refresh_inode
(
inode
,
data
->
res
.
fattr
);
return
0
;
}
...
...
@@ -2603,6 +3026,9 @@ static void nfs4_renew_done(struct rpc_task *task, void *data)
if
(
time_before
(
clp
->
cl_last_renewal
,
timestamp
))
clp
->
cl_last_renewal
=
timestamp
;
spin_unlock
(
&
clp
->
cl_lock
);
dprintk
(
"%s calling put_rpccred on rpc_cred %p
\n
"
,
__func__
,
task
->
tk_msg
.
rpc_cred
);
put_rpccred
(
task
->
tk_msg
.
rpc_cred
);
}
static
const
struct
rpc_call_ops
nfs4_renew_ops
=
{
...
...
@@ -2742,12 +3168,14 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu
.
acl_pages
=
pages
,
.
acl_len
=
buflen
,
};
size_t
resp_len
=
buflen
;
struct
nfs_getaclres
res
=
{
.
acl_len
=
buflen
,
};
void
*
resp_buf
;
struct
rpc_message
msg
=
{
.
rpc_proc
=
&
nfs4_procedures
[
NFSPROC4_CLNT_GETACL
],
.
rpc_argp
=
&
args
,
.
rpc_resp
=
&
res
p_len
,
.
rpc_resp
=
&
res
,
};
struct
page
*
localpage
=
NULL
;
int
ret
;
...
...
@@ -2761,26 +3189,26 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu
return
-
ENOMEM
;
args
.
acl_pages
[
0
]
=
localpage
;
args
.
acl_pgbase
=
0
;
resp_len
=
args
.
acl_len
=
PAGE_SIZE
;
args
.
acl_len
=
PAGE_SIZE
;
}
else
{
resp_buf
=
buf
;
buf_to_pages
(
buf
,
buflen
,
args
.
acl_pages
,
&
args
.
acl_pgbase
);
}
ret
=
rpc_call_sync
(
NFS_CLIENT
(
inode
),
&
msg
,
0
);
ret
=
nfs4_call_sync
(
NFS_SERVER
(
inode
),
&
msg
,
&
args
,
&
res
,
0
);
if
(
ret
)
goto
out_free
;
if
(
res
p
_len
>
args
.
acl_len
)
nfs4_write_cached_acl
(
inode
,
NULL
,
res
p
_len
);
if
(
res
.
acl
_len
>
args
.
acl_len
)
nfs4_write_cached_acl
(
inode
,
NULL
,
res
.
acl
_len
);
else
nfs4_write_cached_acl
(
inode
,
resp_buf
,
res
p
_len
);
nfs4_write_cached_acl
(
inode
,
resp_buf
,
res
.
acl
_len
);
if
(
buf
)
{
ret
=
-
ERANGE
;
if
(
res
p
_len
>
buflen
)
if
(
res
.
acl
_len
>
buflen
)
goto
out_free
;
if
(
localpage
)
memcpy
(
buf
,
resp_buf
,
res
p
_len
);
memcpy
(
buf
,
resp_buf
,
res
.
acl
_len
);
}
ret
=
res
p
_len
;
ret
=
res
.
acl
_len
;
out_free:
if
(
localpage
)
__free_page
(
localpage
);
...
...
@@ -2827,10 +3255,11 @@ static int __nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t bufl
.
acl_pages
=
pages
,
.
acl_len
=
buflen
,
};
struct
nfs_setaclres
res
;
struct
rpc_message
msg
=
{
.
rpc_proc
=
&
nfs4_procedures
[
NFSPROC4_CLNT_SETACL
],
.
rpc_argp
=
&
arg
,
.
rpc_resp
=
NULL
,
.
rpc_resp
=
&
res
,
};
int
ret
;
...
...
@@ -2838,7 +3267,7 @@ static int __nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t bufl
return
-
EOPNOTSUPP
;
nfs_inode_return_delegation
(
inode
);
buf_to_pages
(
buf
,
buflen
,
arg
.
acl_pages
,
&
arg
.
acl_pgbase
);
ret
=
rpc_call_sync
(
NFS_CLIENT
(
inode
),
&
msg
,
0
);
ret
=
nfs4_call_sync
(
server
,
&
msg
,
&
arg
,
&
res
,
1
);
nfs_access_zap_cache
(
inode
);
nfs_zap_acl_cache
(
inode
);
return
ret
;
...
...
@@ -2857,10 +3286,8 @@ static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen
}
static
int
nfs4_async_handle_error
(
struct
rpc_task
*
task
,
const
struct
nfs_server
*
server
,
struct
nfs4_state
*
state
)
_nfs4_async_handle_error
(
struct
rpc_task
*
task
,
const
struct
nfs_server
*
server
,
struct
nfs_client
*
clp
,
struct
nfs4_state
*
state
)
{
struct
nfs_client
*
clp
=
server
->
nfs_client
;
if
(
!
clp
||
task
->
tk_status
>=
0
)
return
0
;
switch
(
task
->
tk_status
)
{
...
...
@@ -2879,7 +3306,22 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server,
rpc_wake_up_queued_task
(
&
clp
->
cl_rpcwaitq
,
task
);
task
->
tk_status
=
0
;
return
-
EAGAIN
;
#if defined(CONFIG_NFS_V4_1)
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
\n
"
,
__func__
,
task
->
tk_status
);
set_bit
(
NFS4CLNT_SESSION_SETUP
,
&
clp
->
cl_state
);
task
->
tk_status
=
0
;
return
-
EAGAIN
;
#endif
/* CONFIG_NFS_V4_1 */
case
-
NFS4ERR_DELAY
:
if
(
server
)
nfs_inc_server_stats
(
server
,
NFSIOS_DELAY
);
case
-
NFS4ERR_GRACE
:
rpc_delay
(
task
,
NFS4_POLL_RETRY_MAX
);
...
...
@@ -2893,6 +3335,12 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server,
return
0
;
}
static
int
nfs4_async_handle_error
(
struct
rpc_task
*
task
,
const
struct
nfs_server
*
server
,
struct
nfs4_state
*
state
)
{
return
_nfs4_async_handle_error
(
task
,
server
,
server
->
nfs_client
,
state
);
}
int
nfs4_proc_setclientid
(
struct
nfs_client
*
clp
,
u32
program
,
unsigned
short
port
,
struct
rpc_cred
*
cred
)
{
nfs4_verifier
sc_verifier
;
...
...
@@ -3000,6 +3448,10 @@ struct nfs4_delegreturndata {
static
void
nfs4_delegreturn_done
(
struct
rpc_task
*
task
,
void
*
calldata
)
{
struct
nfs4_delegreturndata
*
data
=
calldata
;
nfs4_sequence_done_free_slot
(
data
->
res
.
server
,
&
data
->
res
.
seq_res
,
task
->
tk_status
);
data
->
rpc_status
=
task
->
tk_status
;
if
(
data
->
rpc_status
==
0
)
renew_lease
(
data
->
res
.
server
,
data
->
timestamp
);
...
...
@@ -3010,7 +3462,25 @@ static void nfs4_delegreturn_release(void *calldata)
kfree
(
calldata
);
}
#if defined(CONFIG_NFS_V4_1)
static
void
nfs4_delegreturn_prepare
(
struct
rpc_task
*
task
,
void
*
data
)
{
struct
nfs4_delegreturndata
*
d_data
;
d_data
=
(
struct
nfs4_delegreturndata
*
)
data
;
if
(
nfs4_setup_sequence
(
d_data
->
res
.
server
->
nfs_client
,
&
d_data
->
args
.
seq_args
,
&
d_data
->
res
.
seq_res
,
1
,
task
))
return
;
rpc_call_start
(
task
);
}
#endif
/* CONFIG_NFS_V4_1 */
static
const
struct
rpc_call_ops
nfs4_delegreturn_ops
=
{
#if defined(CONFIG_NFS_V4_1)
.
rpc_call_prepare
=
nfs4_delegreturn_prepare
,
#endif
/* CONFIG_NFS_V4_1 */
.
rpc_call_done
=
nfs4_delegreturn_done
,
.
rpc_release
=
nfs4_delegreturn_release
,
};
...
...
@@ -3032,7 +3502,7 @@ static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, co
};
int
status
=
0
;
data
=
k
m
alloc
(
sizeof
(
*
data
),
GFP_KERNEL
);
data
=
k
z
alloc
(
sizeof
(
*
data
),
GFP_KERNEL
);
if
(
data
==
NULL
)
return
-
ENOMEM
;
data
->
args
.
fhandle
=
&
data
->
fh
;
...
...
@@ -3042,6 +3512,7 @@ static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, co
memcpy
(
&
data
->
stateid
,
stateid
,
sizeof
(
data
->
stateid
));
data
->
res
.
fattr
=
&
data
->
fattr
;
data
->
res
.
server
=
server
;
data
->
res
.
seq_res
.
sr_slotid
=
NFS4_MAX_SLOT_TABLE
;
nfs_fattr_init
(
data
->
res
.
fattr
);
data
->
timestamp
=
jiffies
;
data
->
rpc_status
=
0
;
...
...
@@ -3127,7 +3598,7 @@ static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock
goto
out
;
lsp
=
request
->
fl_u
.
nfs4_fl
.
owner
;
arg
.
lock_owner
.
id
=
lsp
->
ls_id
.
id
;
status
=
rpc_call_sync
(
server
->
client
,
&
msg
,
0
);
status
=
nfs4_call_sync
(
server
,
&
msg
,
&
arg
,
&
res
,
1
);
switch
(
status
)
{
case
0
:
request
->
fl_type
=
F_UNLCK
;
...
...
@@ -3187,13 +3658,14 @@ static struct nfs4_unlockdata *nfs4_alloc_unlockdata(struct file_lock *fl,
struct
nfs4_unlockdata
*
p
;
struct
inode
*
inode
=
lsp
->
ls_state
->
inode
;
p
=
k
m
alloc
(
sizeof
(
*
p
),
GFP_KERNEL
);
p
=
k
z
alloc
(
sizeof
(
*
p
),
GFP_KERNEL
);
if
(
p
==
NULL
)
return
NULL
;
p
->
arg
.
fh
=
NFS_FH
(
inode
);
p
->
arg
.
fl
=
&
p
->
fl
;
p
->
arg
.
seqid
=
seqid
;
p
->
res
.
seqid
=
seqid
;
p
->
res
.
seq_res
.
sr_slotid
=
NFS4_MAX_SLOT_TABLE
;
p
->
arg
.
stateid
=
&
lsp
->
ls_stateid
;
p
->
lsp
=
lsp
;
atomic_inc
(
&
lsp
->
ls_count
);
...
...
@@ -3217,6 +3689,8 @@ static void nfs4_locku_done(struct rpc_task *task, void *data)
{
struct
nfs4_unlockdata
*
calldata
=
data
;
nfs4_sequence_done
(
calldata
->
server
,
&
calldata
->
res
.
seq_res
,
task
->
tk_status
);
if
(
RPC_ASSASSINATED
(
task
))
return
;
switch
(
task
->
tk_status
)
{
...
...
@@ -3233,8 +3707,11 @@ static void nfs4_locku_done(struct rpc_task *task, void *data)
break
;
default:
if
(
nfs4_async_handle_error
(
task
,
calldata
->
server
,
NULL
)
==
-
EAGAIN
)
rpc_restart_call
(
task
);
nfs4_restart_rpc
(
task
,
calldata
->
server
->
nfs_client
);
}
nfs4_sequence_free_slot
(
calldata
->
server
->
nfs_client
,
&
calldata
->
res
.
seq_res
);
}
static
void
nfs4_locku_prepare
(
struct
rpc_task
*
task
,
void
*
data
)
...
...
@@ -3249,6 +3726,10 @@ static void nfs4_locku_prepare(struct rpc_task *task, void *data)
return
;
}
calldata
->
timestamp
=
jiffies
;
if
(
nfs4_setup_sequence
(
calldata
->
server
->
nfs_client
,
&
calldata
->
arg
.
seq_args
,
&
calldata
->
res
.
seq_res
,
1
,
task
))
return
;
rpc_call_start
(
task
);
}
...
...
@@ -3341,6 +3822,7 @@ struct nfs4_lockdata {
unsigned
long
timestamp
;
int
rpc_status
;
int
cancelled
;
struct
nfs_server
*
server
;
};
static
struct
nfs4_lockdata
*
nfs4_alloc_lockdata
(
struct
file_lock
*
fl
,
...
...
@@ -3366,7 +3848,9 @@ static struct nfs4_lockdata *nfs4_alloc_lockdata(struct file_lock *fl,
p
->
arg
.
lock_owner
.
clientid
=
server
->
nfs_client
->
cl_clientid
;
p
->
arg
.
lock_owner
.
id
=
lsp
->
ls_id
.
id
;
p
->
res
.
lock_seqid
=
p
->
arg
.
lock_seqid
;
p
->
res
.
seq_res
.
sr_slotid
=
NFS4_MAX_SLOT_TABLE
;
p
->
lsp
=
lsp
;
p
->
server
=
server
;
atomic_inc
(
&
lsp
->
ls_count
);
p
->
ctx
=
get_nfs_open_context
(
ctx
);
memcpy
(
&
p
->
fl
,
fl
,
sizeof
(
p
->
fl
));
...
...
@@ -3396,6 +3880,9 @@ static void nfs4_lock_prepare(struct rpc_task *task, void *calldata)
}
else
data
->
arg
.
new_lock_owner
=
0
;
data
->
timestamp
=
jiffies
;
if
(
nfs4_setup_sequence
(
data
->
server
->
nfs_client
,
&
data
->
arg
.
seq_args
,
&
data
->
res
.
seq_res
,
1
,
task
))
return
;
rpc_call_start
(
task
);
dprintk
(
"%s: done!, ret = %d
\n
"
,
__func__
,
data
->
rpc_status
);
}
...
...
@@ -3406,6 +3893,9 @@ static void nfs4_lock_done(struct rpc_task *task, void *calldata)
dprintk
(
"%s: begin!
\n
"
,
__func__
);
nfs4_sequence_done_free_slot
(
data
->
server
,
&
data
->
res
.
seq_res
,
task
->
tk_status
);
data
->
rpc_status
=
task
->
tk_status
;
if
(
RPC_ASSASSINATED
(
task
))
goto
out
;
...
...
@@ -3706,10 +4196,13 @@ int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name,
.
page
=
page
,
.
bitmask
=
bitmask
,
};
struct
nfs4_fs_locations_res
res
=
{
.
fs_locations
=
fs_locations
,
};
struct
rpc_message
msg
=
{
.
rpc_proc
=
&
nfs4_procedures
[
NFSPROC4_CLNT_FS_LOCATIONS
],
.
rpc_argp
=
&
args
,
.
rpc_resp
=
fs_location
s
,
.
rpc_resp
=
&
re
s
,
};
int
status
;
...
...
@@ -3717,24 +4210,720 @@ int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name,
nfs_fattr_init
(
&
fs_locations
->
fattr
);
fs_locations
->
server
=
server
;
fs_locations
->
nlocations
=
0
;
status
=
rpc_call_sync
(
server
->
client
,
&
msg
,
0
);
status
=
nfs4_call_sync
(
server
,
&
msg
,
&
args
,
&
res
,
0
);
nfs_fixup_referral_attributes
(
&
fs_locations
->
fattr
);
dprintk
(
"%s: returned status = %d
\n
"
,
__func__
,
status
);
return
status
;
}
struct
nfs4_state_recovery_ops
nfs4_reboot_recovery_ops
=
{
#ifdef CONFIG_NFS_V4_1
/*
* nfs4_proc_exchange_id()
*
* Since the clientid has expired, all compounds using sessions
* associated with the stale clientid will be returning
* NFS4ERR_BADSESSION in the sequence operation, and will therefore
* be in some phase of session reset.
*/
static
int
nfs4_proc_exchange_id
(
struct
nfs_client
*
clp
,
struct
rpc_cred
*
cred
)
{
nfs4_verifier
verifier
;
struct
nfs41_exchange_id_args
args
=
{
.
client
=
clp
,
.
flags
=
clp
->
cl_exchange_flags
,
};
struct
nfs41_exchange_id_res
res
=
{
.
client
=
clp
,
};
int
status
;
struct
rpc_message
msg
=
{
.
rpc_proc
=
&
nfs4_procedures
[
NFSPROC4_CLNT_EXCHANGE_ID
],
.
rpc_argp
=
&
args
,
.
rpc_resp
=
&
res
,
.
rpc_cred
=
cred
,
};
__be32
*
p
;
dprintk
(
"--> %s
\n
"
,
__func__
);
BUG_ON
(
clp
==
NULL
);
p
=
(
u32
*
)
verifier
.
data
;
*
p
++
=
htonl
((
u32
)
clp
->
cl_boot_time
.
tv_sec
);
*
p
=
htonl
((
u32
)
clp
->
cl_boot_time
.
tv_nsec
);
args
.
verifier
=
&
verifier
;
while
(
1
)
{
args
.
id_len
=
scnprintf
(
args
.
id
,
sizeof
(
args
.
id
),
"%s/%s %u"
,
clp
->
cl_ipaddr
,
rpc_peeraddr2str
(
clp
->
cl_rpcclient
,
RPC_DISPLAY_ADDR
),
clp
->
cl_id_uniquifier
);
status
=
rpc_call_sync
(
clp
->
cl_rpcclient
,
&
msg
,
0
);
if
(
status
!=
NFS4ERR_CLID_INUSE
)
break
;
if
(
signalled
())
break
;
if
(
++
clp
->
cl_id_uniquifier
==
0
)
break
;
}
dprintk
(
"<-- %s status= %d
\n
"
,
__func__
,
status
);
return
status
;
}
struct
nfs4_get_lease_time_data
{
struct
nfs4_get_lease_time_args
*
args
;
struct
nfs4_get_lease_time_res
*
res
;
struct
nfs_client
*
clp
;
};
static
void
nfs4_get_lease_time_prepare
(
struct
rpc_task
*
task
,
void
*
calldata
)
{
int
ret
;
struct
nfs4_get_lease_time_data
*
data
=
(
struct
nfs4_get_lease_time_data
*
)
calldata
;
dprintk
(
"--> %s
\n
"
,
__func__
);
/* just setup sequence, do not trigger session recovery
since we're invoked within one */
ret
=
nfs41_setup_sequence
(
data
->
clp
->
cl_session
,
&
data
->
args
->
la_seq_args
,
&
data
->
res
->
lr_seq_res
,
0
,
task
);
BUG_ON
(
ret
==
-
EAGAIN
);
rpc_call_start
(
task
);
dprintk
(
"<-- %s
\n
"
,
__func__
);
}
/*
* Called from nfs4_state_manager thread for session setup, so don't recover
* from sequence operation or clientid errors.
*/
static
void
nfs4_get_lease_time_done
(
struct
rpc_task
*
task
,
void
*
calldata
)
{
struct
nfs4_get_lease_time_data
*
data
=
(
struct
nfs4_get_lease_time_data
*
)
calldata
;
dprintk
(
"--> %s
\n
"
,
__func__
);
nfs41_sequence_done
(
data
->
clp
,
&
data
->
res
->
lr_seq_res
,
task
->
tk_status
);
switch
(
task
->
tk_status
)
{
case
-
NFS4ERR_DELAY
:
case
-
NFS4ERR_GRACE
:
dprintk
(
"%s Retry: tk_status %d
\n
"
,
__func__
,
task
->
tk_status
);
rpc_delay
(
task
,
NFS4_POLL_RETRY_MIN
);
task
->
tk_status
=
0
;
nfs4_restart_rpc
(
task
,
data
->
clp
);
return
;
}
nfs41_sequence_free_slot
(
data
->
clp
,
&
data
->
res
->
lr_seq_res
);
dprintk
(
"<-- %s
\n
"
,
__func__
);
}
struct
rpc_call_ops
nfs4_get_lease_time_ops
=
{
.
rpc_call_prepare
=
nfs4_get_lease_time_prepare
,
.
rpc_call_done
=
nfs4_get_lease_time_done
,
};
int
nfs4_proc_get_lease_time
(
struct
nfs_client
*
clp
,
struct
nfs_fsinfo
*
fsinfo
)
{
struct
rpc_task
*
task
;
struct
nfs4_get_lease_time_args
args
;
struct
nfs4_get_lease_time_res
res
=
{
.
lr_fsinfo
=
fsinfo
,
};
struct
nfs4_get_lease_time_data
data
=
{
.
args
=
&
args
,
.
res
=
&
res
,
.
clp
=
clp
,
};
struct
rpc_message
msg
=
{
.
rpc_proc
=
&
nfs4_procedures
[
NFSPROC4_CLNT_GET_LEASE_TIME
],
.
rpc_argp
=
&
args
,
.
rpc_resp
=
&
res
,
};
struct
rpc_task_setup
task_setup
=
{
.
rpc_client
=
clp
->
cl_rpcclient
,
.
rpc_message
=
&
msg
,
.
callback_ops
=
&
nfs4_get_lease_time_ops
,
.
callback_data
=
&
data
};
int
status
;
res
.
lr_seq_res
.
sr_slotid
=
NFS4_MAX_SLOT_TABLE
;
dprintk
(
"--> %s
\n
"
,
__func__
);
task
=
rpc_run_task
(
&
task_setup
);
if
(
IS_ERR
(
task
))
status
=
PTR_ERR
(
task
);
else
{
status
=
task
->
tk_status
;
rpc_put_task
(
task
);
}
dprintk
(
"<-- %s return %d
\n
"
,
__func__
,
status
);
return
status
;
}
/*
* Reset a slot table
*/
static
int
nfs4_reset_slot_table
(
struct
nfs4_slot_table
*
tbl
,
int
max_slots
,
int
old_max_slots
,
int
ivalue
)
{
int
i
;
int
ret
=
0
;
dprintk
(
"--> %s: max_reqs=%u, tbl %p
\n
"
,
__func__
,
max_slots
,
tbl
);
/*
* Until we have dynamic slot table adjustment, insist
* upon the same slot table size
*/
if
(
max_slots
!=
old_max_slots
)
{
dprintk
(
"%s reset slot table does't match old
\n
"
,
__func__
);
ret
=
-
EINVAL
;
/*XXX NFS4ERR_REQ_TOO_BIG ? */
goto
out
;
}
spin_lock
(
&
tbl
->
slot_tbl_lock
);
for
(
i
=
0
;
i
<
max_slots
;
++
i
)
tbl
->
slots
[
i
].
seq_nr
=
ivalue
;
tbl
->
highest_used_slotid
=
-
1
;
spin_unlock
(
&
tbl
->
slot_tbl_lock
);
dprintk
(
"%s: tbl=%p slots=%p max_slots=%d
\n
"
,
__func__
,
tbl
,
tbl
->
slots
,
tbl
->
max_slots
);
out:
dprintk
(
"<-- %s: return %d
\n
"
,
__func__
,
ret
);
return
ret
;
}
/*
* Reset the forechannel and backchannel slot tables
*/
static
int
nfs4_reset_slot_tables
(
struct
nfs4_session
*
session
)
{
int
status
;
status
=
nfs4_reset_slot_table
(
&
session
->
fc_slot_table
,
session
->
fc_attrs
.
max_reqs
,
session
->
fc_slot_table
.
max_slots
,
1
);
if
(
status
)
return
status
;
status
=
nfs4_reset_slot_table
(
&
session
->
bc_slot_table
,
session
->
bc_attrs
.
max_reqs
,
session
->
bc_slot_table
.
max_slots
,
0
);
return
status
;
}
/* Destroy the slot table */
static
void
nfs4_destroy_slot_tables
(
struct
nfs4_session
*
session
)
{
if
(
session
->
fc_slot_table
.
slots
!=
NULL
)
{
kfree
(
session
->
fc_slot_table
.
slots
);
session
->
fc_slot_table
.
slots
=
NULL
;
}
if
(
session
->
bc_slot_table
.
slots
!=
NULL
)
{
kfree
(
session
->
bc_slot_table
.
slots
);
session
->
bc_slot_table
.
slots
=
NULL
;
}
return
;
}
/*
* Initialize slot table
*/
static
int
nfs4_init_slot_table
(
struct
nfs4_slot_table
*
tbl
,
int
max_slots
,
int
ivalue
)
{
int
i
;
struct
nfs4_slot
*
slot
;
int
ret
=
-
ENOMEM
;
BUG_ON
(
max_slots
>
NFS4_MAX_SLOT_TABLE
);
dprintk
(
"--> %s: max_reqs=%u
\n
"
,
__func__
,
max_slots
);
slot
=
kcalloc
(
max_slots
,
sizeof
(
struct
nfs4_slot
),
GFP_KERNEL
);
if
(
!
slot
)
goto
out
;
for
(
i
=
0
;
i
<
max_slots
;
++
i
)
slot
[
i
].
seq_nr
=
ivalue
;
ret
=
0
;
spin_lock
(
&
tbl
->
slot_tbl_lock
);
if
(
tbl
->
slots
!=
NULL
)
{
spin_unlock
(
&
tbl
->
slot_tbl_lock
);
dprintk
(
"%s: slot table already initialized. tbl=%p slots=%p
\n
"
,
__func__
,
tbl
,
tbl
->
slots
);
WARN_ON
(
1
);
goto
out_free
;
}
tbl
->
max_slots
=
max_slots
;
tbl
->
slots
=
slot
;
tbl
->
highest_used_slotid
=
-
1
;
/* no slot is currently used */
spin_unlock
(
&
tbl
->
slot_tbl_lock
);
dprintk
(
"%s: tbl=%p slots=%p max_slots=%d
\n
"
,
__func__
,
tbl
,
tbl
->
slots
,
tbl
->
max_slots
);
out:
dprintk
(
"<-- %s: return %d
\n
"
,
__func__
,
ret
);
return
ret
;
out_free:
kfree
(
slot
);
goto
out
;
}
/*
* Initialize the forechannel and backchannel tables
*/
static
int
nfs4_init_slot_tables
(
struct
nfs4_session
*
session
)
{
int
status
;
status
=
nfs4_init_slot_table
(
&
session
->
fc_slot_table
,
session
->
fc_attrs
.
max_reqs
,
1
);
if
(
status
)
return
status
;
status
=
nfs4_init_slot_table
(
&
session
->
bc_slot_table
,
session
->
bc_attrs
.
max_reqs
,
0
);
if
(
status
)
nfs4_destroy_slot_tables
(
session
);
return
status
;
}
struct
nfs4_session
*
nfs4_alloc_session
(
struct
nfs_client
*
clp
)
{
struct
nfs4_session
*
session
;
struct
nfs4_slot_table
*
tbl
;
session
=
kzalloc
(
sizeof
(
struct
nfs4_session
),
GFP_KERNEL
);
if
(
!
session
)
return
NULL
;
set_bit
(
NFS4CLNT_SESSION_SETUP
,
&
clp
->
cl_state
);
/*
* The create session reply races with the server back
* channel probe. Mark the client NFS_CS_SESSION_INITING
* so that the client back channel can find the
* nfs_client struct
*/
clp
->
cl_cons_state
=
NFS_CS_SESSION_INITING
;
tbl
=
&
session
->
fc_slot_table
;
spin_lock_init
(
&
tbl
->
slot_tbl_lock
);
rpc_init_wait_queue
(
&
tbl
->
slot_tbl_waitq
,
"ForeChannel Slot table"
);
tbl
=
&
session
->
bc_slot_table
;
spin_lock_init
(
&
tbl
->
slot_tbl_lock
);
rpc_init_wait_queue
(
&
tbl
->
slot_tbl_waitq
,
"BackChannel Slot table"
);
session
->
clp
=
clp
;
return
session
;
}
void
nfs4_destroy_session
(
struct
nfs4_session
*
session
)
{
nfs4_proc_destroy_session
(
session
);
dprintk
(
"%s Destroy backchannel for xprt %p
\n
"
,
__func__
,
session
->
clp
->
cl_rpcclient
->
cl_xprt
);
xprt_destroy_backchannel
(
session
->
clp
->
cl_rpcclient
->
cl_xprt
,
NFS41_BC_MIN_CALLBACKS
);
nfs4_destroy_slot_tables
(
session
);
kfree
(
session
);
}
/*
* Initialize the values to be used by the client in CREATE_SESSION
* If nfs4_init_session set the fore channel request and response sizes,
* use them.
*
* Set the back channel max_resp_sz_cached to zero to force the client to
* always set csa_cachethis to FALSE because the current implementation
* of the back channel DRC only supports caching the CB_SEQUENCE operation.
*/
static
void
nfs4_init_channel_attrs
(
struct
nfs41_create_session_args
*
args
)
{
struct
nfs4_session
*
session
=
args
->
client
->
cl_session
;
unsigned
int
mxrqst_sz
=
session
->
fc_attrs
.
max_rqst_sz
,
mxresp_sz
=
session
->
fc_attrs
.
max_resp_sz
;
if
(
mxrqst_sz
==
0
)
mxrqst_sz
=
NFS_MAX_FILE_IO_SIZE
;
if
(
mxresp_sz
==
0
)
mxresp_sz
=
NFS_MAX_FILE_IO_SIZE
;
/* Fore channel attributes */
args
->
fc_attrs
.
headerpadsz
=
0
;
args
->
fc_attrs
.
max_rqst_sz
=
mxrqst_sz
;
args
->
fc_attrs
.
max_resp_sz
=
mxresp_sz
;
args
->
fc_attrs
.
max_resp_sz_cached
=
mxresp_sz
;
args
->
fc_attrs
.
max_ops
=
NFS4_MAX_OPS
;
args
->
fc_attrs
.
max_reqs
=
session
->
clp
->
cl_rpcclient
->
cl_xprt
->
max_reqs
;
dprintk
(
"%s: Fore Channel : max_rqst_sz=%u max_resp_sz=%u "
"max_resp_sz_cached=%u max_ops=%u max_reqs=%u
\n
"
,
__func__
,
args
->
fc_attrs
.
max_rqst_sz
,
args
->
fc_attrs
.
max_resp_sz
,
args
->
fc_attrs
.
max_resp_sz_cached
,
args
->
fc_attrs
.
max_ops
,
args
->
fc_attrs
.
max_reqs
);
/* Back channel attributes */
args
->
bc_attrs
.
headerpadsz
=
0
;
args
->
bc_attrs
.
max_rqst_sz
=
PAGE_SIZE
;
args
->
bc_attrs
.
max_resp_sz
=
PAGE_SIZE
;
args
->
bc_attrs
.
max_resp_sz_cached
=
0
;
args
->
bc_attrs
.
max_ops
=
NFS4_MAX_BACK_CHANNEL_OPS
;
args
->
bc_attrs
.
max_reqs
=
1
;
dprintk
(
"%s: Back Channel : max_rqst_sz=%u max_resp_sz=%u "
"max_resp_sz_cached=%u max_ops=%u max_reqs=%u
\n
"
,
__func__
,
args
->
bc_attrs
.
max_rqst_sz
,
args
->
bc_attrs
.
max_resp_sz
,
args
->
bc_attrs
.
max_resp_sz_cached
,
args
->
bc_attrs
.
max_ops
,
args
->
bc_attrs
.
max_reqs
);
}
static
int
_verify_channel_attr
(
char
*
chan
,
char
*
attr_name
,
u32
sent
,
u32
rcvd
)
{
if
(
rcvd
<=
sent
)
return
0
;
printk
(
KERN_WARNING
"%s: Session INVALID: %s channel %s increased. "
"sent=%u rcvd=%u
\n
"
,
__func__
,
chan
,
attr_name
,
sent
,
rcvd
);
return
-
EINVAL
;
}
#define _verify_fore_channel_attr(_name_) \
_verify_channel_attr("fore", #_name_, \
args->fc_attrs._name_, \
session->fc_attrs._name_)
#define _verify_back_channel_attr(_name_) \
_verify_channel_attr("back", #_name_, \
args->bc_attrs._name_, \
session->bc_attrs._name_)
/*
* The server is not allowed to increase the fore channel header pad size,
* maximum response size, or maximum number of operations.
*
* The back channel attributes are only negotiatied down: We send what the
* (back channel) server insists upon.
*/
static
int
nfs4_verify_channel_attrs
(
struct
nfs41_create_session_args
*
args
,
struct
nfs4_session
*
session
)
{
int
ret
=
0
;
ret
|=
_verify_fore_channel_attr
(
headerpadsz
);
ret
|=
_verify_fore_channel_attr
(
max_resp_sz
);
ret
|=
_verify_fore_channel_attr
(
max_ops
);
ret
|=
_verify_back_channel_attr
(
headerpadsz
);
ret
|=
_verify_back_channel_attr
(
max_rqst_sz
);
ret
|=
_verify_back_channel_attr
(
max_resp_sz
);
ret
|=
_verify_back_channel_attr
(
max_resp_sz_cached
);
ret
|=
_verify_back_channel_attr
(
max_ops
);
ret
|=
_verify_back_channel_attr
(
max_reqs
);
return
ret
;
}
static
int
_nfs4_proc_create_session
(
struct
nfs_client
*
clp
)
{
struct
nfs4_session
*
session
=
clp
->
cl_session
;
struct
nfs41_create_session_args
args
=
{
.
client
=
clp
,
.
cb_program
=
NFS4_CALLBACK
,
};
struct
nfs41_create_session_res
res
=
{
.
client
=
clp
,
};
struct
rpc_message
msg
=
{
.
rpc_proc
=
&
nfs4_procedures
[
NFSPROC4_CLNT_CREATE_SESSION
],
.
rpc_argp
=
&
args
,
.
rpc_resp
=
&
res
,
};
int
status
;
nfs4_init_channel_attrs
(
&
args
);
args
.
flags
=
(
SESSION4_PERSIST
|
SESSION4_BACK_CHAN
);
status
=
rpc_call_sync
(
session
->
clp
->
cl_rpcclient
,
&
msg
,
0
);
if
(
!
status
)
/* Verify the session's negotiated channel_attrs values */
status
=
nfs4_verify_channel_attrs
(
&
args
,
session
);
if
(
!
status
)
{
/* Increment the clientid slot sequence id */
clp
->
cl_seqid
++
;
}
return
status
;
}
/*
* Issues a CREATE_SESSION operation to the server.
* It is the responsibility of the caller to verify the session is
* expired before calling this routine.
*/
int
nfs4_proc_create_session
(
struct
nfs_client
*
clp
,
int
reset
)
{
int
status
;
unsigned
*
ptr
;
struct
nfs_fsinfo
fsinfo
;
struct
nfs4_session
*
session
=
clp
->
cl_session
;
dprintk
(
"--> %s clp=%p session=%p
\n
"
,
__func__
,
clp
,
session
);
status
=
_nfs4_proc_create_session
(
clp
);
if
(
status
)
goto
out
;
/* Init or reset the fore channel */
if
(
reset
)
status
=
nfs4_reset_slot_tables
(
session
);
else
status
=
nfs4_init_slot_tables
(
session
);
dprintk
(
"fore channel slot table initialization returned %d
\n
"
,
status
);
if
(
status
)
goto
out
;
ptr
=
(
unsigned
*
)
&
session
->
sess_id
.
data
[
0
];
dprintk
(
"%s client>seqid %d sessionid %u:%u:%u:%u
\n
"
,
__func__
,
clp
->
cl_seqid
,
ptr
[
0
],
ptr
[
1
],
ptr
[
2
],
ptr
[
3
]);
if
(
reset
)
/* Lease time is aleady set */
goto
out
;
/* Get the lease time */
status
=
nfs4_proc_get_lease_time
(
clp
,
&
fsinfo
);
if
(
status
==
0
)
{
/* Update lease time and schedule renewal */
spin_lock
(
&
clp
->
cl_lock
);
clp
->
cl_lease_time
=
fsinfo
.
lease_time
*
HZ
;
clp
->
cl_last_renewal
=
jiffies
;
clear_bit
(
NFS4CLNT_LEASE_EXPIRED
,
&
clp
->
cl_state
);
spin_unlock
(
&
clp
->
cl_lock
);
nfs4_schedule_state_renewal
(
clp
);
}
out:
dprintk
(
"<-- %s
\n
"
,
__func__
);
return
status
;
}
/*
* Issue the over-the-wire RPC DESTROY_SESSION.
* The caller must serialize access to this routine.
*/
int
nfs4_proc_destroy_session
(
struct
nfs4_session
*
session
)
{
int
status
=
0
;
struct
rpc_message
msg
;
dprintk
(
"--> nfs4_proc_destroy_session
\n
"
);
/* session is still being setup */
if
(
session
->
clp
->
cl_cons_state
!=
NFS_CS_READY
)
return
status
;
msg
.
rpc_proc
=
&
nfs4_procedures
[
NFSPROC4_CLNT_DESTROY_SESSION
];
msg
.
rpc_argp
=
session
;
msg
.
rpc_resp
=
NULL
;
msg
.
rpc_cred
=
NULL
;
status
=
rpc_call_sync
(
session
->
clp
->
cl_rpcclient
,
&
msg
,
0
);
if
(
status
)
printk
(
KERN_WARNING
"Got error %d from the server on DESTROY_SESSION. "
"Session has been destroyed regardless...
\n
"
,
status
);
dprintk
(
"<-- nfs4_proc_destroy_session
\n
"
);
return
status
;
}
/*
* Renew the cl_session lease.
*/
static
int
nfs4_proc_sequence
(
struct
nfs_client
*
clp
,
struct
rpc_cred
*
cred
)
{
struct
nfs4_sequence_args
args
;
struct
nfs4_sequence_res
res
;
struct
rpc_message
msg
=
{
.
rpc_proc
=
&
nfs4_procedures
[
NFSPROC4_CLNT_SEQUENCE
],
.
rpc_argp
=
&
args
,
.
rpc_resp
=
&
res
,
.
rpc_cred
=
cred
,
};
args
.
sa_cache_this
=
0
;
return
nfs4_call_sync_sequence
(
clp
,
clp
->
cl_rpcclient
,
&
msg
,
&
args
,
&
res
,
0
);
}
void
nfs41_sequence_call_done
(
struct
rpc_task
*
task
,
void
*
data
)
{
struct
nfs_client
*
clp
=
(
struct
nfs_client
*
)
data
;
nfs41_sequence_done
(
clp
,
task
->
tk_msg
.
rpc_resp
,
task
->
tk_status
);
if
(
task
->
tk_status
<
0
)
{
dprintk
(
"%s ERROR %d
\n
"
,
__func__
,
task
->
tk_status
);
if
(
_nfs4_async_handle_error
(
task
,
NULL
,
clp
,
NULL
)
==
-
EAGAIN
)
{
nfs4_restart_rpc
(
task
,
clp
);
return
;
}
}
nfs41_sequence_free_slot
(
clp
,
task
->
tk_msg
.
rpc_resp
);
dprintk
(
"%s rpc_cred %p
\n
"
,
__func__
,
task
->
tk_msg
.
rpc_cred
);
put_rpccred
(
task
->
tk_msg
.
rpc_cred
);
kfree
(
task
->
tk_msg
.
rpc_argp
);
kfree
(
task
->
tk_msg
.
rpc_resp
);
dprintk
(
"<-- %s
\n
"
,
__func__
);
}
static
void
nfs41_sequence_prepare
(
struct
rpc_task
*
task
,
void
*
data
)
{
struct
nfs_client
*
clp
;
struct
nfs4_sequence_args
*
args
;
struct
nfs4_sequence_res
*
res
;
clp
=
(
struct
nfs_client
*
)
data
;
args
=
task
->
tk_msg
.
rpc_argp
;
res
=
task
->
tk_msg
.
rpc_resp
;
if
(
nfs4_setup_sequence
(
clp
,
args
,
res
,
0
,
task
))
return
;
rpc_call_start
(
task
);
}
static
const
struct
rpc_call_ops
nfs41_sequence_ops
=
{
.
rpc_call_done
=
nfs41_sequence_call_done
,
.
rpc_call_prepare
=
nfs41_sequence_prepare
,
};
static
int
nfs41_proc_async_sequence
(
struct
nfs_client
*
clp
,
struct
rpc_cred
*
cred
)
{
struct
nfs4_sequence_args
*
args
;
struct
nfs4_sequence_res
*
res
;
struct
rpc_message
msg
=
{
.
rpc_proc
=
&
nfs4_procedures
[
NFSPROC4_CLNT_SEQUENCE
],
.
rpc_cred
=
cred
,
};
args
=
kzalloc
(
sizeof
(
*
args
),
GFP_KERNEL
);
if
(
!
args
)
return
-
ENOMEM
;
res
=
kzalloc
(
sizeof
(
*
res
),
GFP_KERNEL
);
if
(
!
res
)
{
kfree
(
args
);
return
-
ENOMEM
;
}
res
->
sr_slotid
=
NFS4_MAX_SLOT_TABLE
;
msg
.
rpc_argp
=
args
;
msg
.
rpc_resp
=
res
;
return
rpc_call_async
(
clp
->
cl_rpcclient
,
&
msg
,
RPC_TASK_SOFT
,
&
nfs41_sequence_ops
,
(
void
*
)
clp
);
}
#endif
/* CONFIG_NFS_V4_1 */
struct
nfs4_state_recovery_ops
nfs40_reboot_recovery_ops
=
{
.
owner_flag_bit
=
NFS_OWNER_RECLAIM_REBOOT
,
.
state_flag_bit
=
NFS_STATE_RECLAIM_REBOOT
,
.
recover_open
=
nfs4_open_reclaim
,
.
recover_lock
=
nfs4_lock_reclaim
,
.
establish_clid
=
nfs4_init_clientid
,
.
get_clid_cred
=
nfs4_get_setclientid_cred
,
};
#if defined(CONFIG_NFS_V4_1)
struct
nfs4_state_recovery_ops
nfs41_reboot_recovery_ops
=
{
.
owner_flag_bit
=
NFS_OWNER_RECLAIM_REBOOT
,
.
state_flag_bit
=
NFS_STATE_RECLAIM_REBOOT
,
.
recover_open
=
nfs4_open_reclaim
,
.
recover_lock
=
nfs4_lock_reclaim
,
.
establish_clid
=
nfs4_proc_exchange_id
,
.
get_clid_cred
=
nfs4_get_exchange_id_cred
,
};
#endif
/* CONFIG_NFS_V4_1 */
struct
nfs4_state_recovery_ops
nfs40_nograce_recovery_ops
=
{
.
owner_flag_bit
=
NFS_OWNER_RECLAIM_NOGRACE
,
.
state_flag_bit
=
NFS_STATE_RECLAIM_NOGRACE
,
.
recover_open
=
nfs4_open_expired
,
.
recover_lock
=
nfs4_lock_expired
,
.
establish_clid
=
nfs4_init_clientid
,
.
get_clid_cred
=
nfs4_get_setclientid_cred
,
};
struct
nfs4_state_recovery_ops
nfs4_nograce_recovery_ops
=
{
#if defined(CONFIG_NFS_V4_1)
struct
nfs4_state_recovery_ops
nfs41_nograce_recovery_ops
=
{
.
owner_flag_bit
=
NFS_OWNER_RECLAIM_NOGRACE
,
.
state_flag_bit
=
NFS_STATE_RECLAIM_NOGRACE
,
.
recover_open
=
nfs4_open_expired
,
.
recover_lock
=
nfs4_lock_expired
,
.
establish_clid
=
nfs4_proc_exchange_id
,
.
get_clid_cred
=
nfs4_get_exchange_id_cred
,
};
#endif
/* CONFIG_NFS_V4_1 */
struct
nfs4_state_maintenance_ops
nfs40_state_renewal_ops
=
{
.
sched_state_renewal
=
nfs4_proc_async_renew
,
.
get_state_renewal_cred_locked
=
nfs4_get_renew_cred_locked
,
.
renew_lease
=
nfs4_proc_renew
,
};
#if defined(CONFIG_NFS_V4_1)
struct
nfs4_state_maintenance_ops
nfs41_state_renewal_ops
=
{
.
sched_state_renewal
=
nfs41_proc_async_sequence
,
.
get_state_renewal_cred_locked
=
nfs4_get_machine_cred_locked
,
.
renew_lease
=
nfs4_proc_sequence
,
};
#endif
/*
* Per minor version reboot and network partition recovery ops
*/
struct
nfs4_state_recovery_ops
*
nfs4_reboot_recovery_ops
[]
=
{
&
nfs40_reboot_recovery_ops
,
#if defined(CONFIG_NFS_V4_1)
&
nfs41_reboot_recovery_ops
,
#endif
};
struct
nfs4_state_recovery_ops
*
nfs4_nograce_recovery_ops
[]
=
{
&
nfs40_nograce_recovery_ops
,
#if defined(CONFIG_NFS_V4_1)
&
nfs41_nograce_recovery_ops
,
#endif
};
struct
nfs4_state_maintenance_ops
*
nfs4_state_renewal_ops
[]
=
{
&
nfs40_state_renewal_ops
,
#if defined(CONFIG_NFS_V4_1)
&
nfs41_state_renewal_ops
,
#endif
};
static
const
struct
inode_operations
nfs4_file_inode_operations
=
{
...
...
fs/nfs/nfs4renewd.c
View file @
301933a0
...
...
@@ -59,12 +59,14 @@
void
nfs4_renew_state
(
struct
work_struct
*
work
)
{
struct
nfs4_state_maintenance_ops
*
ops
;
struct
nfs_client
*
clp
=
container_of
(
work
,
struct
nfs_client
,
cl_renewd
.
work
);
struct
rpc_cred
*
cred
;
long
lease
,
timeout
;
unsigned
long
last
,
now
;
ops
=
nfs4_state_renewal_ops
[
clp
->
cl_minorversion
];
dprintk
(
"%s: start
\n
"
,
__func__
);
/* Are there any active superblocks? */
if
(
list_empty
(
&
clp
->
cl_superblocks
))
...
...
@@ -76,7 +78,7 @@ nfs4_renew_state(struct work_struct *work)
timeout
=
(
2
*
lease
)
/
3
+
(
long
)
last
-
(
long
)
now
;
/* Are we close to a lease timeout? */
if
(
time_after
(
now
,
last
+
lease
/
3
))
{
cred
=
nfs4_get_renew
_cred_locked
(
clp
);
cred
=
ops
->
get_state_renewal
_cred_locked
(
clp
);
spin_unlock
(
&
clp
->
cl_lock
);
if
(
cred
==
NULL
)
{
if
(
list_empty
(
&
clp
->
cl_delegations
))
{
...
...
@@ -86,7 +88,7 @@ nfs4_renew_state(struct work_struct *work)
nfs_expire_all_delegations
(
clp
);
}
else
{
/* Queue an asynchronous RENEW. */
nfs4_proc_async_renew
(
clp
,
cred
);
ops
->
sched_state_renewal
(
clp
,
cred
);
put_rpccred
(
cred
);
}
timeout
=
(
2
*
lease
)
/
3
;
...
...
fs/nfs/nfs4state.c
View file @
301933a0
...
...
@@ -60,7 +60,7 @@ const nfs4_stateid zero_stateid;
static
LIST_HEAD
(
nfs4_clientid_list
);
static
int
nfs4_init_client
(
struct
nfs_client
*
clp
,
struct
rpc_cred
*
cred
)
int
nfs4_init_clientid
(
struct
nfs_client
*
clp
,
struct
rpc_cred
*
cred
)
{
unsigned
short
port
;
int
status
;
...
...
@@ -77,7 +77,7 @@ static int nfs4_init_client(struct nfs_client *clp, struct rpc_cred *cred)
return
status
;
}
st
atic
st
ruct
rpc_cred
*
nfs4_get_machine_cred_locked
(
struct
nfs_client
*
clp
)
struct
rpc_cred
*
nfs4_get_machine_cred_locked
(
struct
nfs_client
*
clp
)
{
struct
rpc_cred
*
cred
=
NULL
;
...
...
@@ -114,17 +114,21 @@ struct rpc_cred *nfs4_get_renew_cred_locked(struct nfs_client *clp)
return
cred
;
}
static
struct
rpc_cred
*
nfs4_get_renew_cred
(
struct
nfs_client
*
clp
)
#if defined(CONFIG_NFS_V4_1)
struct
rpc_cred
*
nfs4_get_exchange_id_cred
(
struct
nfs_client
*
clp
)
{
struct
rpc_cred
*
cred
;
spin_lock
(
&
clp
->
cl_lock
);
cred
=
nfs4_get_
renew
_cred_locked
(
clp
);
cred
=
nfs4_get_
machine
_cred_locked
(
clp
);
spin_unlock
(
&
clp
->
cl_lock
);
return
cred
;
}
static
struct
rpc_cred
*
nfs4_get_setclientid_cred
(
struct
nfs_client
*
clp
)
#endif
/* CONFIG_NFS_V4_1 */
struct
rpc_cred
*
nfs4_get_setclientid_cred
(
struct
nfs_client
*
clp
)
{
struct
nfs4_state_owner
*
sp
;
struct
rb_node
*
pos
;
...
...
@@ -738,11 +742,13 @@ static void nfs_increment_seqid(int status, struct nfs_seqid *seqid)
void
nfs_increment_open_seqid
(
int
status
,
struct
nfs_seqid
*
seqid
)
{
if
(
status
==
-
NFS4ERR_BAD_SEQID
)
{
struct
nfs4_state_owner
*
sp
=
container_of
(
seqid
->
sequence
,
struct
nfs4_state_owner
,
so_seqid
);
struct
nfs_server
*
server
=
sp
->
so_server
;
if
(
status
==
-
NFS4ERR_BAD_SEQID
)
nfs4_drop_state_owner
(
sp
);
}
if
(
!
nfs4_has_session
(
server
->
nfs_client
))
nfs_increment_seqid
(
status
,
seqid
);
}
...
...
@@ -1042,6 +1048,14 @@ static void nfs4_recovery_handle_error(struct nfs_client *clp, int error)
case
-
NFS4ERR_EXPIRED
:
set_bit
(
NFS4CLNT_LEASE_EXPIRED
,
&
clp
->
cl_state
);
nfs4_state_start_reclaim_nograce
(
clp
);
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
:
set_bit
(
NFS4CLNT_SESSION_SETUP
,
&
clp
->
cl_state
);
}
}
...
...
@@ -1075,18 +1089,22 @@ static int nfs4_do_reclaim(struct nfs_client *clp, const struct nfs4_state_recov
static
int
nfs4_check_lease
(
struct
nfs_client
*
clp
)
{
struct
rpc_cred
*
cred
;
struct
nfs4_state_maintenance_ops
*
ops
=
nfs4_state_renewal_ops
[
clp
->
cl_minorversion
];
int
status
=
-
NFS4ERR_EXPIRED
;
/* Is the client already known to have an expired lease? */
if
(
test_bit
(
NFS4CLNT_LEASE_EXPIRED
,
&
clp
->
cl_state
))
return
0
;
cred
=
nfs4_get_renew_cred
(
clp
);
spin_lock
(
&
clp
->
cl_lock
);
cred
=
ops
->
get_state_renewal_cred_locked
(
clp
);
spin_unlock
(
&
clp
->
cl_lock
);
if
(
cred
==
NULL
)
{
cred
=
nfs4_get_setclientid_cred
(
clp
);
if
(
cred
==
NULL
)
goto
out
;
}
status
=
nfs4_proc_renew
(
clp
,
cred
);
status
=
ops
->
renew_lease
(
clp
,
cred
);
put_rpccred
(
cred
);
out:
nfs4_recovery_handle_error
(
clp
,
status
);
...
...
@@ -1096,20 +1114,97 @@ static int nfs4_check_lease(struct nfs_client *clp)
static
int
nfs4_reclaim_lease
(
struct
nfs_client
*
clp
)
{
struct
rpc_cred
*
cred
;
struct
nfs4_state_recovery_ops
*
ops
=
nfs4_reboot_recovery_ops
[
clp
->
cl_minorversion
];
int
status
=
-
ENOENT
;
cred
=
nfs4_get_setclient
id_cred
(
clp
);
cred
=
ops
->
get_cl
id_cred
(
clp
);
if
(
cred
!=
NULL
)
{
status
=
nfs4_init_client
(
clp
,
cred
);
status
=
ops
->
establish_clid
(
clp
,
cred
);
put_rpccred
(
cred
);
/* Handle case where the user hasn't set up machine creds */
if
(
status
==
-
EACCES
&&
cred
==
clp
->
cl_machine_cred
)
{
nfs4_clear_machine_cred
(
clp
);
status
=
-
EAGAIN
;
}
if
(
status
==
-
NFS4ERR_MINOR_VERS_MISMATCH
)
status
=
-
EPROTONOSUPPORT
;
}
return
status
;
}
#ifdef CONFIG_NFS_V4_1
static
void
nfs4_session_recovery_handle_error
(
struct
nfs_client
*
clp
,
int
err
)
{
switch
(
err
)
{
case
-
NFS4ERR_STALE_CLIENTID
:
set_bit
(
NFS4CLNT_LEASE_EXPIRED
,
&
clp
->
cl_state
);
set_bit
(
NFS4CLNT_SESSION_SETUP
,
&
clp
->
cl_state
);
}
}
static
int
nfs4_reset_session
(
struct
nfs_client
*
clp
)
{
int
status
;
status
=
nfs4_proc_destroy_session
(
clp
->
cl_session
);
if
(
status
&&
status
!=
-
NFS4ERR_BADSESSION
&&
status
!=
-
NFS4ERR_DEADSESSION
)
{
nfs4_session_recovery_handle_error
(
clp
,
status
);
goto
out
;
}
memset
(
clp
->
cl_session
->
sess_id
.
data
,
0
,
NFS4_MAX_SESSIONID_LEN
);
status
=
nfs4_proc_create_session
(
clp
,
1
);
if
(
status
)
nfs4_session_recovery_handle_error
(
clp
,
status
);
/* fall through*/
out:
/* Wake up the next rpc task even on error */
rpc_wake_up_next
(
&
clp
->
cl_session
->
fc_slot_table
.
slot_tbl_waitq
);
return
status
;
}
static
int
nfs4_initialize_session
(
struct
nfs_client
*
clp
)
{
int
status
;
status
=
nfs4_proc_create_session
(
clp
,
0
);
if
(
!
status
)
{
nfs_mark_client_ready
(
clp
,
NFS_CS_READY
);
}
else
if
(
status
==
-
NFS4ERR_STALE_CLIENTID
)
{
set_bit
(
NFS4CLNT_LEASE_EXPIRED
,
&
clp
->
cl_state
);
set_bit
(
NFS4CLNT_SESSION_SETUP
,
&
clp
->
cl_state
);
}
else
{
nfs_mark_client_ready
(
clp
,
status
);
}
return
status
;
}
#else
/* CONFIG_NFS_V4_1 */
static
int
nfs4_reset_session
(
struct
nfs_client
*
clp
)
{
return
0
;
}
static
int
nfs4_initialize_session
(
struct
nfs_client
*
clp
)
{
return
0
;
}
#endif
/* CONFIG_NFS_V4_1 */
/* Set NFS4CLNT_LEASE_EXPIRED for all v4.0 errors and for recoverable errors
* on EXCHANGE_ID for v4.1
*/
static
void
nfs4_set_lease_expired
(
struct
nfs_client
*
clp
,
int
status
)
{
if
(
nfs4_has_session
(
clp
))
{
switch
(
status
)
{
case
-
NFS4ERR_DELAY
:
case
-
NFS4ERR_CLID_INUSE
:
case
-
EAGAIN
:
break
;
case
-
NFS4ERR_NOT_SAME
:
/* FixMe: implement recovery
* in nfs4_exchange_id */
default:
return
;
}
}
set_bit
(
NFS4CLNT_LEASE_EXPIRED
,
&
clp
->
cl_state
);
}
static
void
nfs4_state_manager
(
struct
nfs_client
*
clp
)
{
...
...
@@ -1121,9 +1216,12 @@ static void nfs4_state_manager(struct nfs_client *clp)
/* We're going to have to re-establish a clientid */
status
=
nfs4_reclaim_lease
(
clp
);
if
(
status
)
{
set_bit
(
NFS4CLNT_LEASE_EXPIRED
,
&
clp
->
cl_state
);
nfs4_set_lease_expired
(
clp
,
status
);
if
(
status
==
-
EAGAIN
)
continue
;
if
(
clp
->
cl_cons_state
==
NFS_CS_SESSION_INITING
)
nfs_mark_client_ready
(
clp
,
status
);
goto
out_error
;
}
clear_bit
(
NFS4CLNT_CHECK_LEASE
,
&
clp
->
cl_state
);
...
...
@@ -1134,25 +1232,44 @@ static void nfs4_state_manager(struct nfs_client *clp)
if
(
status
!=
0
)
continue
;
}
/* Initialize or reset the session */
if
(
nfs4_has_session
(
clp
)
&&
test_and_clear_bit
(
NFS4CLNT_SESSION_SETUP
,
&
clp
->
cl_state
))
{
if
(
clp
->
cl_cons_state
==
NFS_CS_SESSION_INITING
)
status
=
nfs4_initialize_session
(
clp
);
else
status
=
nfs4_reset_session
(
clp
);
if
(
status
)
{
if
(
status
==
-
NFS4ERR_STALE_CLIENTID
)
continue
;
goto
out_error
;
}
}
/* First recover reboot state... */
if
(
test_and_clear_bit
(
NFS4CLNT_RECLAIM_REBOOT
,
&
clp
->
cl_state
))
{
status
=
nfs4_do_reclaim
(
clp
,
&
nfs4_reboot_recovery_ops
);
status
=
nfs4_do_reclaim
(
clp
,
nfs4_reboot_recovery_ops
[
clp
->
cl_minorversion
]);
if
(
status
==
-
NFS4ERR_STALE_CLIENTID
)
continue
;
if
(
test_bit
(
NFS4CLNT_SESSION_SETUP
,
&
clp
->
cl_state
))
continue
;
nfs4_state_end_reclaim_reboot
(
clp
);
continue
;
}
/* Now recover expired state... */
if
(
test_and_clear_bit
(
NFS4CLNT_RECLAIM_NOGRACE
,
&
clp
->
cl_state
))
{
status
=
nfs4_do_reclaim
(
clp
,
&
nfs4_nograce_recovery_ops
);
status
=
nfs4_do_reclaim
(
clp
,
nfs4_nograce_recovery_ops
[
clp
->
cl_minorversion
]);
if
(
status
<
0
)
{
set_bit
(
NFS4CLNT_RECLAIM_NOGRACE
,
&
clp
->
cl_state
);
if
(
status
==
-
NFS4ERR_STALE_CLIENTID
)
continue
;
if
(
status
==
-
NFS4ERR_EXPIRED
)
continue
;
if
(
test_bit
(
NFS4CLNT_SESSION_SETUP
,
&
clp
->
cl_state
))
continue
;
goto
out_error
;
}
else
nfs4_state_end_reclaim_nograce
(
clp
);
...
...
fs/nfs/nfs4xdr.c
View file @
301933a0
...
...
@@ -192,12 +192,16 @@ static int nfs4_stat_to_errno(int);
decode_verifier_maxsz)
#define encode_remove_maxsz (op_encode_hdr_maxsz + \
nfs4_name_maxsz)
#define decode_remove_maxsz (op_decode_hdr_maxsz + \
decode_change_info_maxsz)
#define encode_rename_maxsz (op_encode_hdr_maxsz + \
2 * nfs4_name_maxsz)
#define decode_rename_maxsz (op_decode_hdr_maxsz + 5 + 5)
#define decode_rename_maxsz (op_decode_hdr_maxsz + \
decode_change_info_maxsz + \
decode_change_info_maxsz)
#define encode_link_maxsz (op_encode_hdr_maxsz + \
nfs4_name_maxsz)
#define decode_link_maxsz (op_decode_hdr_maxsz +
5
)
#define decode_link_maxsz (op_decode_hdr_maxsz +
decode_change_info_maxsz
)
#define encode_lock_maxsz (op_encode_hdr_maxsz + \
7 + \
1 + encode_stateid_maxsz + 8)
...
...
@@ -240,43 +244,115 @@ static int nfs4_stat_to_errno(int);
(encode_getattr_maxsz)
#define decode_fs_locations_maxsz \
(0)
#if defined(CONFIG_NFS_V4_1)
#define NFS4_MAX_MACHINE_NAME_LEN (64)
#define encode_exchange_id_maxsz (op_encode_hdr_maxsz + \
encode_verifier_maxsz + \
1
/* co_ownerid.len */
+ \
XDR_QUADLEN(NFS4_EXCHANGE_ID_LEN) + \
1
/* flags */
+ \
1
/* spa_how */
+ \
0
/* SP4_NONE (for now) */
+ \
1
/* zero implemetation id array */
)
#define decode_exchange_id_maxsz (op_decode_hdr_maxsz + \
2
/* eir_clientid */
+ \
1
/* eir_sequenceid */
+ \
1
/* eir_flags */
+ \
1
/* spr_how */
+ \
0
/* SP4_NONE (for now) */
+ \
2
/* eir_server_owner.so_minor_id */
+ \
/* eir_server_owner.so_major_id<> */
\
XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + 1 + \
/* eir_server_scope<> */
\
XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + 1 + \
1
/* eir_server_impl_id array length */
+ \
0
/* ignored eir_server_impl_id contents */
)
#define encode_channel_attrs_maxsz (6 + 1
/* ca_rdma_ird.len (0) */
)
#define decode_channel_attrs_maxsz (6 + \
1
/* ca_rdma_ird.len */
+ \
1
/* ca_rdma_ird */
)
#define encode_create_session_maxsz (op_encode_hdr_maxsz + \
2
/* csa_clientid */
+ \
1
/* csa_sequence */
+ \
1
/* csa_flags */
+ \
encode_channel_attrs_maxsz + \
encode_channel_attrs_maxsz + \
1
/* csa_cb_program */
+ \
1
/* csa_sec_parms.len (1) */
+ \
1
/* cb_secflavor (AUTH_SYS) */
+ \
1
/* stamp */
+ \
1
/* machinename.len */
+ \
XDR_QUADLEN(NFS4_MAX_MACHINE_NAME_LEN) + \
1
/* uid */
+ \
1
/* gid */
+ \
1
/* gids.len (0) */
)
#define decode_create_session_maxsz (op_decode_hdr_maxsz + \
XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + \
1
/* csr_sequence */
+ \
1
/* csr_flags */
+ \
decode_channel_attrs_maxsz + \
decode_channel_attrs_maxsz)
#define encode_destroy_session_maxsz (op_encode_hdr_maxsz + 4)
#define decode_destroy_session_maxsz (op_decode_hdr_maxsz)
#define encode_sequence_maxsz (op_encode_hdr_maxsz + \
XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + 4)
#define decode_sequence_maxsz (op_decode_hdr_maxsz + \
XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + 5)
#else
/* CONFIG_NFS_V4_1 */
#define encode_sequence_maxsz 0
#define decode_sequence_maxsz 0
#endif
/* CONFIG_NFS_V4_1 */
#define NFS4_enc_compound_sz (1024)
/* XXX: large enough? */
#define NFS4_dec_compound_sz (1024)
/* XXX: large enough? */
#define NFS4_enc_read_sz (compound_encode_hdr_maxsz + \
encode_sequence_maxsz + \
encode_putfh_maxsz + \
encode_read_maxsz)
#define NFS4_dec_read_sz (compound_decode_hdr_maxsz + \
decode_sequence_maxsz + \
decode_putfh_maxsz + \
decode_read_maxsz)
#define NFS4_enc_readlink_sz (compound_encode_hdr_maxsz + \
encode_sequence_maxsz + \
encode_putfh_maxsz + \
encode_readlink_maxsz)
#define NFS4_dec_readlink_sz (compound_decode_hdr_maxsz + \
decode_sequence_maxsz + \
decode_putfh_maxsz + \
decode_readlink_maxsz)
#define NFS4_enc_readdir_sz (compound_encode_hdr_maxsz + \
encode_sequence_maxsz + \
encode_putfh_maxsz + \
encode_readdir_maxsz)
#define NFS4_dec_readdir_sz (compound_decode_hdr_maxsz + \
decode_sequence_maxsz + \
decode_putfh_maxsz + \
decode_readdir_maxsz)
#define NFS4_enc_write_sz (compound_encode_hdr_maxsz + \
encode_sequence_maxsz + \
encode_putfh_maxsz + \
encode_write_maxsz + \
encode_getattr_maxsz)
#define NFS4_dec_write_sz (compound_decode_hdr_maxsz + \
decode_sequence_maxsz + \
decode_putfh_maxsz + \
decode_write_maxsz + \
decode_getattr_maxsz)
#define NFS4_enc_commit_sz (compound_encode_hdr_maxsz + \
encode_sequence_maxsz + \
encode_putfh_maxsz + \
encode_commit_maxsz + \
encode_getattr_maxsz)
#define NFS4_dec_commit_sz (compound_decode_hdr_maxsz + \
decode_sequence_maxsz + \
decode_putfh_maxsz + \
decode_commit_maxsz + \
decode_getattr_maxsz)
#define NFS4_enc_open_sz (compound_encode_hdr_maxsz + \
encode_sequence_maxsz + \
encode_putfh_maxsz + \
encode_savefh_maxsz + \
encode_open_maxsz + \
...
...
@@ -285,6 +361,7 @@ static int nfs4_stat_to_errno(int);
encode_restorefh_maxsz + \
encode_getattr_maxsz)
#define NFS4_dec_open_sz (compound_decode_hdr_maxsz + \
decode_sequence_maxsz + \
decode_putfh_maxsz + \
decode_savefh_maxsz + \
decode_open_maxsz + \
...
...
@@ -301,43 +378,53 @@ static int nfs4_stat_to_errno(int);
decode_putfh_maxsz + \
decode_open_confirm_maxsz)
#define NFS4_enc_open_noattr_sz (compound_encode_hdr_maxsz + \
encode_sequence_maxsz + \
encode_putfh_maxsz + \
encode_open_maxsz + \
encode_getattr_maxsz)
#define NFS4_dec_open_noattr_sz (compound_decode_hdr_maxsz + \
decode_sequence_maxsz + \
decode_putfh_maxsz + \
decode_open_maxsz + \
decode_getattr_maxsz)
#define NFS4_enc_open_downgrade_sz \
(compound_encode_hdr_maxsz + \
encode_sequence_maxsz + \
encode_putfh_maxsz + \
encode_open_downgrade_maxsz + \
encode_getattr_maxsz)
#define NFS4_dec_open_downgrade_sz \
(compound_decode_hdr_maxsz + \
decode_sequence_maxsz + \
decode_putfh_maxsz + \
decode_open_downgrade_maxsz + \
decode_getattr_maxsz)
#define NFS4_enc_close_sz (compound_encode_hdr_maxsz + \
encode_sequence_maxsz + \
encode_putfh_maxsz + \
encode_close_maxsz + \
encode_getattr_maxsz)
#define NFS4_dec_close_sz (compound_decode_hdr_maxsz + \
decode_sequence_maxsz + \
decode_putfh_maxsz + \
decode_close_maxsz + \
decode_getattr_maxsz)
#define NFS4_enc_setattr_sz (compound_encode_hdr_maxsz + \
encode_sequence_maxsz + \
encode_putfh_maxsz + \
encode_setattr_maxsz + \
encode_getattr_maxsz)
#define NFS4_dec_setattr_sz (compound_decode_hdr_maxsz + \
decode_sequence_maxsz + \
decode_putfh_maxsz + \
decode_setattr_maxsz + \
decode_getattr_maxsz)
#define NFS4_enc_fsinfo_sz (compound_encode_hdr_maxsz + \
encode_sequence_maxsz + \
encode_putfh_maxsz + \
encode_fsinfo_maxsz)
#define NFS4_dec_fsinfo_sz (compound_decode_hdr_maxsz + \
decode_sequence_maxsz + \
decode_putfh_maxsz + \
decode_fsinfo_maxsz)
#define NFS4_enc_renew_sz (compound_encode_hdr_maxsz + \
...
...
@@ -359,64 +446,81 @@ static int nfs4_stat_to_errno(int);
decode_putrootfh_maxsz + \
decode_fsinfo_maxsz)
#define NFS4_enc_lock_sz (compound_encode_hdr_maxsz + \
encode_sequence_maxsz + \
encode_putfh_maxsz + \
encode_lock_maxsz)
#define NFS4_dec_lock_sz (compound_decode_hdr_maxsz + \
decode_sequence_maxsz + \
decode_putfh_maxsz + \
decode_lock_maxsz)
#define NFS4_enc_lockt_sz (compound_encode_hdr_maxsz + \
encode_sequence_maxsz + \
encode_putfh_maxsz + \
encode_lockt_maxsz)
#define NFS4_dec_lockt_sz (compound_decode_hdr_maxsz + \
decode_sequence_maxsz + \
decode_putfh_maxsz + \
decode_lockt_maxsz)
#define NFS4_enc_locku_sz (compound_encode_hdr_maxsz + \
encode_sequence_maxsz + \
encode_putfh_maxsz + \
encode_locku_maxsz)
#define NFS4_dec_locku_sz (compound_decode_hdr_maxsz + \
decode_sequence_maxsz + \
decode_putfh_maxsz + \
decode_locku_maxsz)
#define NFS4_enc_access_sz (compound_encode_hdr_maxsz + \
encode_sequence_maxsz + \
encode_putfh_maxsz + \
encode_access_maxsz + \
encode_getattr_maxsz)
#define NFS4_dec_access_sz (compound_decode_hdr_maxsz + \
decode_sequence_maxsz + \
decode_putfh_maxsz + \
decode_access_maxsz + \
decode_getattr_maxsz)
#define NFS4_enc_getattr_sz (compound_encode_hdr_maxsz + \
encode_sequence_maxsz + \
encode_putfh_maxsz + \
encode_getattr_maxsz)
#define NFS4_dec_getattr_sz (compound_decode_hdr_maxsz + \
decode_sequence_maxsz + \
decode_putfh_maxsz + \
decode_getattr_maxsz)
#define NFS4_enc_lookup_sz (compound_encode_hdr_maxsz + \
encode_sequence_maxsz + \
encode_putfh_maxsz + \
encode_lookup_maxsz + \
encode_getattr_maxsz + \
encode_getfh_maxsz)
#define NFS4_dec_lookup_sz (compound_decode_hdr_maxsz + \
decode_sequence_maxsz + \
decode_putfh_maxsz + \
decode_lookup_maxsz + \
decode_getattr_maxsz + \
decode_getfh_maxsz)
#define NFS4_enc_lookup_root_sz (compound_encode_hdr_maxsz + \
encode_sequence_maxsz + \
encode_putrootfh_maxsz + \
encode_getattr_maxsz + \
encode_getfh_maxsz)
#define NFS4_dec_lookup_root_sz (compound_decode_hdr_maxsz + \
decode_sequence_maxsz + \
decode_putrootfh_maxsz + \
decode_getattr_maxsz + \
decode_getfh_maxsz)
#define NFS4_enc_remove_sz (compound_encode_hdr_maxsz + \
encode_sequence_maxsz + \
encode_putfh_maxsz + \
encode_remove_maxsz + \
encode_getattr_maxsz)
#define NFS4_dec_remove_sz (compound_decode_hdr_maxsz + \
decode_sequence_maxsz + \
decode_putfh_maxsz + \
op_decode_hdr_maxsz + 5
+ \
decode_remove_maxsz
+ \
decode_getattr_maxsz)
#define NFS4_enc_rename_sz (compound_encode_hdr_maxsz + \
encode_sequence_maxsz + \
encode_putfh_maxsz + \
encode_savefh_maxsz + \
encode_putfh_maxsz + \
...
...
@@ -425,6 +529,7 @@ static int nfs4_stat_to_errno(int);
encode_restorefh_maxsz + \
encode_getattr_maxsz)
#define NFS4_dec_rename_sz (compound_decode_hdr_maxsz + \
decode_sequence_maxsz + \
decode_putfh_maxsz + \
decode_savefh_maxsz + \
decode_putfh_maxsz + \
...
...
@@ -433,6 +538,7 @@ static int nfs4_stat_to_errno(int);
decode_restorefh_maxsz + \
decode_getattr_maxsz)
#define NFS4_enc_link_sz (compound_encode_hdr_maxsz + \
encode_sequence_maxsz + \
encode_putfh_maxsz + \
encode_savefh_maxsz + \
encode_putfh_maxsz + \
...
...
@@ -441,6 +547,7 @@ static int nfs4_stat_to_errno(int);
encode_restorefh_maxsz + \
decode_getattr_maxsz)
#define NFS4_dec_link_sz (compound_decode_hdr_maxsz + \
decode_sequence_maxsz + \
decode_putfh_maxsz + \
decode_savefh_maxsz + \
decode_putfh_maxsz + \
...
...
@@ -449,16 +556,19 @@ static int nfs4_stat_to_errno(int);
decode_restorefh_maxsz + \
decode_getattr_maxsz)
#define NFS4_enc_symlink_sz (compound_encode_hdr_maxsz + \
encode_sequence_maxsz + \
encode_putfh_maxsz + \
encode_symlink_maxsz + \
encode_getattr_maxsz + \
encode_getfh_maxsz)
#define NFS4_dec_symlink_sz (compound_decode_hdr_maxsz + \
decode_sequence_maxsz + \
decode_putfh_maxsz + \
decode_symlink_maxsz + \
decode_getattr_maxsz + \
decode_getfh_maxsz)
#define NFS4_enc_create_sz (compound_encode_hdr_maxsz + \
encode_sequence_maxsz + \
encode_putfh_maxsz + \
encode_savefh_maxsz + \
encode_create_maxsz + \
...
...
@@ -467,6 +577,7 @@ static int nfs4_stat_to_errno(int);
encode_restorefh_maxsz + \
encode_getattr_maxsz)
#define NFS4_dec_create_sz (compound_decode_hdr_maxsz + \
decode_sequence_maxsz + \
decode_putfh_maxsz + \
decode_savefh_maxsz + \
decode_create_maxsz + \
...
...
@@ -475,52 +586,98 @@ static int nfs4_stat_to_errno(int);
decode_restorefh_maxsz + \
decode_getattr_maxsz)
#define NFS4_enc_pathconf_sz (compound_encode_hdr_maxsz + \
encode_sequence_maxsz + \
encode_putfh_maxsz + \
encode_getattr_maxsz)
#define NFS4_dec_pathconf_sz (compound_decode_hdr_maxsz + \
decode_sequence_maxsz + \
decode_putfh_maxsz + \
decode_getattr_maxsz)
#define NFS4_enc_statfs_sz (compound_encode_hdr_maxsz + \
encode_sequence_maxsz + \
encode_putfh_maxsz + \
encode_statfs_maxsz)
#define NFS4_dec_statfs_sz (compound_decode_hdr_maxsz + \
decode_sequence_maxsz + \
decode_putfh_maxsz + \
decode_statfs_maxsz)
#define NFS4_enc_server_caps_sz (compound_encode_hdr_maxsz + \
encode_sequence_maxsz + \
encode_putfh_maxsz + \
encode_getattr_maxsz)
#define NFS4_dec_server_caps_sz (compound_decode_hdr_maxsz + \
decode_sequence_maxsz + \
decode_putfh_maxsz + \
decode_getattr_maxsz)
#define NFS4_enc_delegreturn_sz (compound_encode_hdr_maxsz + \
encode_sequence_maxsz + \
encode_putfh_maxsz + \
encode_delegreturn_maxsz + \
encode_getattr_maxsz)
#define NFS4_dec_delegreturn_sz (compound_decode_hdr_maxsz + \
decode_sequence_maxsz + \
decode_delegreturn_maxsz + \
decode_getattr_maxsz)
#define NFS4_enc_getacl_sz (compound_encode_hdr_maxsz + \
encode_sequence_maxsz + \
encode_putfh_maxsz + \
encode_getacl_maxsz)
#define NFS4_dec_getacl_sz (compound_decode_hdr_maxsz + \
decode_sequence_maxsz + \
decode_putfh_maxsz + \
decode_getacl_maxsz)
#define NFS4_enc_setacl_sz (compound_encode_hdr_maxsz + \
encode_sequence_maxsz + \
encode_putfh_maxsz + \
encode_setacl_maxsz)
#define NFS4_dec_setacl_sz (compound_decode_hdr_maxsz + \
decode_sequence_maxsz + \
decode_putfh_maxsz + \
decode_setacl_maxsz)
#define NFS4_enc_fs_locations_sz \
(compound_encode_hdr_maxsz + \
encode_sequence_maxsz + \
encode_putfh_maxsz + \
encode_lookup_maxsz + \
encode_fs_locations_maxsz)
#define NFS4_dec_fs_locations_sz \
(compound_decode_hdr_maxsz + \
decode_sequence_maxsz + \
decode_putfh_maxsz + \
decode_lookup_maxsz + \
decode_fs_locations_maxsz)
#if defined(CONFIG_NFS_V4_1)
#define NFS4_enc_exchange_id_sz \
(compound_encode_hdr_maxsz + \
encode_exchange_id_maxsz)
#define NFS4_dec_exchange_id_sz \
(compound_decode_hdr_maxsz + \
decode_exchange_id_maxsz)
#define NFS4_enc_create_session_sz \
(compound_encode_hdr_maxsz + \
encode_create_session_maxsz)
#define NFS4_dec_create_session_sz \
(compound_decode_hdr_maxsz + \
decode_create_session_maxsz)
#define NFS4_enc_destroy_session_sz (compound_encode_hdr_maxsz + \
encode_destroy_session_maxsz)
#define NFS4_dec_destroy_session_sz (compound_decode_hdr_maxsz + \
decode_destroy_session_maxsz)
#define NFS4_enc_sequence_sz \
(compound_decode_hdr_maxsz + \
encode_sequence_maxsz)
#define NFS4_dec_sequence_sz \
(compound_decode_hdr_maxsz + \
decode_sequence_maxsz)
#define NFS4_enc_get_lease_time_sz (compound_encode_hdr_maxsz + \
encode_sequence_maxsz + \
encode_putrootfh_maxsz + \
encode_fsinfo_maxsz)
#define NFS4_dec_get_lease_time_sz (compound_decode_hdr_maxsz + \
decode_sequence_maxsz + \
decode_putrootfh_maxsz + \
decode_fsinfo_maxsz)
#endif
/* CONFIG_NFS_V4_1 */
static
const
umode_t
nfs_type2fmt
[]
=
{
[
NF4BAD
]
=
0
,
...
...
@@ -541,6 +698,8 @@ struct compound_hdr {
__be32
*
nops_p
;
uint32_t
taglen
;
char
*
tag
;
uint32_t
replen
;
/* expected reply words */
u32
minorversion
;
};
/*
...
...
@@ -576,22 +735,31 @@ static void encode_string(struct xdr_stream *xdr, unsigned int len, const char *
xdr_encode_opaque
(
p
,
str
,
len
);
}
static
void
encode_compound_hdr
(
struct
xdr_stream
*
xdr
,
struct
compound_hdr
*
hdr
)
static
void
encode_compound_hdr
(
struct
xdr_stream
*
xdr
,
struct
rpc_rqst
*
req
,
struct
compound_hdr
*
hdr
)
{
__be32
*
p
;
struct
rpc_auth
*
auth
=
req
->
rq_task
->
tk_msg
.
rpc_cred
->
cr_auth
;
/* initialize running count of expected bytes in reply.
* NOTE: the replied tag SHOULD be the same is the one sent,
* but this is not required as a MUST for the server to do so. */
hdr
->
replen
=
RPC_REPHDRSIZE
+
auth
->
au_rslack
+
3
+
hdr
->
taglen
;
dprintk
(
"encode_compound: tag=%.*s
\n
"
,
(
int
)
hdr
->
taglen
,
hdr
->
tag
);
BUG_ON
(
hdr
->
taglen
>
NFS4_MAXTAGLEN
);
RESERVE_SPACE
(
12
+
(
XDR_QUADLEN
(
hdr
->
taglen
)
<<
2
));
WRITE32
(
hdr
->
taglen
);
WRITEMEM
(
hdr
->
tag
,
hdr
->
taglen
);
WRITE32
(
NFS4_MINOR_VERSION
);
WRITE32
(
hdr
->
minorversion
);
hdr
->
nops_p
=
p
;
WRITE32
(
hdr
->
nops
);
}
static
void
encode_nops
(
struct
compound_hdr
*
hdr
)
{
BUG_ON
(
hdr
->
nops
>
NFS4_MAX_OPS
);
*
hdr
->
nops_p
=
htonl
(
hdr
->
nops
);
}
...
...
@@ -736,6 +904,7 @@ static void encode_access(struct xdr_stream *xdr, u32 access, struct compound_hd
WRITE32
(
OP_ACCESS
);
WRITE32
(
access
);
hdr
->
nops
++
;
hdr
->
replen
+=
decode_access_maxsz
;
}
static
void
encode_close
(
struct
xdr_stream
*
xdr
,
const
struct
nfs_closeargs
*
arg
,
struct
compound_hdr
*
hdr
)
...
...
@@ -747,6 +916,7 @@ static void encode_close(struct xdr_stream *xdr, const struct nfs_closeargs *arg
WRITE32
(
arg
->
seqid
->
sequence
->
counter
);
WRITEMEM
(
arg
->
stateid
->
data
,
NFS4_STATEID_SIZE
);
hdr
->
nops
++
;
hdr
->
replen
+=
decode_close_maxsz
;
}
static
void
encode_commit
(
struct
xdr_stream
*
xdr
,
const
struct
nfs_writeargs
*
args
,
struct
compound_hdr
*
hdr
)
...
...
@@ -758,6 +928,7 @@ static void encode_commit(struct xdr_stream *xdr, const struct nfs_writeargs *ar
WRITE64
(
args
->
offset
);
WRITE32
(
args
->
count
);
hdr
->
nops
++
;
hdr
->
replen
+=
decode_commit_maxsz
;
}
static
void
encode_create
(
struct
xdr_stream
*
xdr
,
const
struct
nfs4_create_arg
*
create
,
struct
compound_hdr
*
hdr
)
...
...
@@ -789,6 +960,7 @@ static void encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *
WRITE32
(
create
->
name
->
len
);
WRITEMEM
(
create
->
name
->
name
,
create
->
name
->
len
);
hdr
->
nops
++
;
hdr
->
replen
+=
decode_create_maxsz
;
encode_attrs
(
xdr
,
create
->
attrs
,
create
->
server
);
}
...
...
@@ -802,6 +974,7 @@ static void encode_getattr_one(struct xdr_stream *xdr, uint32_t bitmap, struct c
WRITE32
(
1
);
WRITE32
(
bitmap
);
hdr
->
nops
++
;
hdr
->
replen
+=
decode_getattr_maxsz
;
}
static
void
encode_getattr_two
(
struct
xdr_stream
*
xdr
,
uint32_t
bm0
,
uint32_t
bm1
,
struct
compound_hdr
*
hdr
)
...
...
@@ -814,6 +987,7 @@ static void encode_getattr_two(struct xdr_stream *xdr, uint32_t bm0, uint32_t bm
WRITE32
(
bm0
);
WRITE32
(
bm1
);
hdr
->
nops
++
;
hdr
->
replen
+=
decode_getattr_maxsz
;
}
static
void
encode_getfattr
(
struct
xdr_stream
*
xdr
,
const
u32
*
bitmask
,
struct
compound_hdr
*
hdr
)
...
...
@@ -841,6 +1015,7 @@ static void encode_getfh(struct xdr_stream *xdr, struct compound_hdr *hdr)
RESERVE_SPACE
(
4
);
WRITE32
(
OP_GETFH
);
hdr
->
nops
++
;
hdr
->
replen
+=
decode_getfh_maxsz
;
}
static
void
encode_link
(
struct
xdr_stream
*
xdr
,
const
struct
qstr
*
name
,
struct
compound_hdr
*
hdr
)
...
...
@@ -852,6 +1027,7 @@ static void encode_link(struct xdr_stream *xdr, const struct qstr *name, struct
WRITE32
(
name
->
len
);
WRITEMEM
(
name
->
name
,
name
->
len
);
hdr
->
nops
++
;
hdr
->
replen
+=
decode_link_maxsz
;
}
static
inline
int
nfs4_lock_type
(
struct
file_lock
*
fl
,
int
block
)
...
...
@@ -899,6 +1075,7 @@ static void encode_lock(struct xdr_stream *xdr, const struct nfs_lock_args *args
WRITE32
(
args
->
lock_seqid
->
sequence
->
counter
);
}
hdr
->
nops
++
;
hdr
->
replen
+=
decode_lock_maxsz
;
}
static
void
encode_lockt
(
struct
xdr_stream
*
xdr
,
const
struct
nfs_lockt_args
*
args
,
struct
compound_hdr
*
hdr
)
...
...
@@ -915,6 +1092,7 @@ static void encode_lockt(struct xdr_stream *xdr, const struct nfs_lockt_args *ar
WRITEMEM
(
"lock id:"
,
8
);
WRITE64
(
args
->
lock_owner
.
id
);
hdr
->
nops
++
;
hdr
->
replen
+=
decode_lockt_maxsz
;
}
static
void
encode_locku
(
struct
xdr_stream
*
xdr
,
const
struct
nfs_locku_args
*
args
,
struct
compound_hdr
*
hdr
)
...
...
@@ -929,6 +1107,7 @@ static void encode_locku(struct xdr_stream *xdr, const struct nfs_locku_args *ar
WRITE64
(
args
->
fl
->
fl_start
);
WRITE64
(
nfs4_lock_length
(
args
->
fl
));
hdr
->
nops
++
;
hdr
->
replen
+=
decode_locku_maxsz
;
}
static
void
encode_lookup
(
struct
xdr_stream
*
xdr
,
const
struct
qstr
*
name
,
struct
compound_hdr
*
hdr
)
...
...
@@ -941,6 +1120,7 @@ static void encode_lookup(struct xdr_stream *xdr, const struct qstr *name, struc
WRITE32
(
len
);
WRITEMEM
(
name
->
name
,
len
);
hdr
->
nops
++
;
hdr
->
replen
+=
decode_lookup_maxsz
;
}
static
void
encode_share_access
(
struct
xdr_stream
*
xdr
,
fmode_t
fmode
)
...
...
@@ -1080,6 +1260,7 @@ static void encode_open(struct xdr_stream *xdr, const struct nfs_openargs *arg,
BUG
();
}
hdr
->
nops
++
;
hdr
->
replen
+=
decode_open_maxsz
;
}
static
void
encode_open_confirm
(
struct
xdr_stream
*
xdr
,
const
struct
nfs_open_confirmargs
*
arg
,
struct
compound_hdr
*
hdr
)
...
...
@@ -1091,6 +1272,7 @@ static void encode_open_confirm(struct xdr_stream *xdr, const struct nfs_open_co
WRITEMEM
(
arg
->
stateid
->
data
,
NFS4_STATEID_SIZE
);
WRITE32
(
arg
->
seqid
->
sequence
->
counter
);
hdr
->
nops
++
;
hdr
->
replen
+=
decode_open_confirm_maxsz
;
}
static
void
encode_open_downgrade
(
struct
xdr_stream
*
xdr
,
const
struct
nfs_closeargs
*
arg
,
struct
compound_hdr
*
hdr
)
...
...
@@ -1103,6 +1285,7 @@ static void encode_open_downgrade(struct xdr_stream *xdr, const struct nfs_close
WRITE32
(
arg
->
seqid
->
sequence
->
counter
);
encode_share_access
(
xdr
,
arg
->
fmode
);
hdr
->
nops
++
;
hdr
->
replen
+=
decode_open_downgrade_maxsz
;
}
static
void
...
...
@@ -1116,6 +1299,7 @@ encode_putfh(struct xdr_stream *xdr, const struct nfs_fh *fh, struct compound_hd
WRITE32
(
len
);
WRITEMEM
(
fh
->
data
,
len
);
hdr
->
nops
++
;
hdr
->
replen
+=
decode_putfh_maxsz
;
}
static
void
encode_putrootfh
(
struct
xdr_stream
*
xdr
,
struct
compound_hdr
*
hdr
)
...
...
@@ -1125,6 +1309,7 @@ static void encode_putrootfh(struct xdr_stream *xdr, struct compound_hdr *hdr)
RESERVE_SPACE
(
4
);
WRITE32
(
OP_PUTROOTFH
);
hdr
->
nops
++
;
hdr
->
replen
+=
decode_putrootfh_maxsz
;
}
static
void
encode_stateid
(
struct
xdr_stream
*
xdr
,
const
struct
nfs_open_context
*
ctx
)
...
...
@@ -1153,6 +1338,7 @@ static void encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args,
WRITE64
(
args
->
offset
);
WRITE32
(
args
->
count
);
hdr
->
nops
++
;
hdr
->
replen
+=
decode_read_maxsz
;
}
static
void
encode_readdir
(
struct
xdr_stream
*
xdr
,
const
struct
nfs4_readdir_arg
*
readdir
,
struct
rpc_rqst
*
req
,
struct
compound_hdr
*
hdr
)
...
...
@@ -1178,6 +1364,7 @@ static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg
WRITE32
(
attrs
[
0
]
&
readdir
->
bitmask
[
0
]);
WRITE32
(
attrs
[
1
]
&
readdir
->
bitmask
[
1
]);
hdr
->
nops
++
;
hdr
->
replen
+=
decode_readdir_maxsz
;
dprintk
(
"%s: cookie = %Lu, verifier = %08x:%08x, bitmap = %08x:%08x
\n
"
,
__func__
,
(
unsigned
long
long
)
readdir
->
cookie
,
...
...
@@ -1194,6 +1381,7 @@ static void encode_readlink(struct xdr_stream *xdr, const struct nfs4_readlink *
RESERVE_SPACE
(
4
);
WRITE32
(
OP_READLINK
);
hdr
->
nops
++
;
hdr
->
replen
+=
decode_readlink_maxsz
;
}
static
void
encode_remove
(
struct
xdr_stream
*
xdr
,
const
struct
qstr
*
name
,
struct
compound_hdr
*
hdr
)
...
...
@@ -1205,6 +1393,7 @@ static void encode_remove(struct xdr_stream *xdr, const struct qstr *name, struc
WRITE32
(
name
->
len
);
WRITEMEM
(
name
->
name
,
name
->
len
);
hdr
->
nops
++
;
hdr
->
replen
+=
decode_remove_maxsz
;
}
static
void
encode_rename
(
struct
xdr_stream
*
xdr
,
const
struct
qstr
*
oldname
,
const
struct
qstr
*
newname
,
struct
compound_hdr
*
hdr
)
...
...
@@ -1220,6 +1409,7 @@ static void encode_rename(struct xdr_stream *xdr, const struct qstr *oldname, co
WRITE32
(
newname
->
len
);
WRITEMEM
(
newname
->
name
,
newname
->
len
);
hdr
->
nops
++
;
hdr
->
replen
+=
decode_rename_maxsz
;
}
static
void
encode_renew
(
struct
xdr_stream
*
xdr
,
const
struct
nfs_client
*
client_stateid
,
struct
compound_hdr
*
hdr
)
...
...
@@ -1230,6 +1420,7 @@ static void encode_renew(struct xdr_stream *xdr, const struct nfs_client *client
WRITE32
(
OP_RENEW
);
WRITE64
(
client_stateid
->
cl_clientid
);
hdr
->
nops
++
;
hdr
->
replen
+=
decode_renew_maxsz
;
}
static
void
...
...
@@ -1240,6 +1431,7 @@ encode_restorefh(struct xdr_stream *xdr, struct compound_hdr *hdr)
RESERVE_SPACE
(
4
);
WRITE32
(
OP_RESTOREFH
);
hdr
->
nops
++
;
hdr
->
replen
+=
decode_restorefh_maxsz
;
}
static
int
...
...
@@ -1259,6 +1451,7 @@ encode_setacl(struct xdr_stream *xdr, struct nfs_setaclargs *arg, struct compoun
WRITE32
(
arg
->
acl_len
);
xdr_write_pages
(
xdr
,
arg
->
acl_pages
,
arg
->
acl_pgbase
,
arg
->
acl_len
);
hdr
->
nops
++
;
hdr
->
replen
+=
decode_setacl_maxsz
;
return
0
;
}
...
...
@@ -1270,6 +1463,7 @@ encode_savefh(struct xdr_stream *xdr, struct compound_hdr *hdr)
RESERVE_SPACE
(
4
);
WRITE32
(
OP_SAVEFH
);
hdr
->
nops
++
;
hdr
->
replen
+=
decode_savefh_maxsz
;
}
static
void
encode_setattr
(
struct
xdr_stream
*
xdr
,
const
struct
nfs_setattrargs
*
arg
,
const
struct
nfs_server
*
server
,
struct
compound_hdr
*
hdr
)
...
...
@@ -1280,6 +1474,7 @@ static void encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs
WRITE32
(
OP_SETATTR
);
WRITEMEM
(
arg
->
stateid
.
data
,
NFS4_STATEID_SIZE
);
hdr
->
nops
++
;
hdr
->
replen
+=
decode_setattr_maxsz
;
encode_attrs
(
xdr
,
arg
->
iap
,
server
);
}
...
...
@@ -1299,6 +1494,7 @@ static void encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclie
RESERVE_SPACE
(
4
);
WRITE32
(
setclientid
->
sc_cb_ident
);
hdr
->
nops
++
;
hdr
->
replen
+=
decode_setclientid_maxsz
;
}
static
void
encode_setclientid_confirm
(
struct
xdr_stream
*
xdr
,
const
struct
nfs_client
*
client_state
,
struct
compound_hdr
*
hdr
)
...
...
@@ -1310,6 +1506,7 @@ static void encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs_
WRITE64
(
client_state
->
cl_clientid
);
WRITEMEM
(
client_state
->
cl_confirm
.
data
,
NFS4_VERIFIER_SIZE
);
hdr
->
nops
++
;
hdr
->
replen
+=
decode_setclientid_confirm_maxsz
;
}
static
void
encode_write
(
struct
xdr_stream
*
xdr
,
const
struct
nfs_writeargs
*
args
,
struct
compound_hdr
*
hdr
)
...
...
@@ -1328,6 +1525,7 @@ static void encode_write(struct xdr_stream *xdr, const struct nfs_writeargs *arg
xdr_write_pages
(
xdr
,
args
->
pages
,
args
->
pgbase
,
args
->
count
);
hdr
->
nops
++
;
hdr
->
replen
+=
decode_write_maxsz
;
}
static
void
encode_delegreturn
(
struct
xdr_stream
*
xdr
,
const
nfs4_stateid
*
stateid
,
struct
compound_hdr
*
hdr
)
...
...
@@ -1339,11 +1537,163 @@ static void encode_delegreturn(struct xdr_stream *xdr, const nfs4_stateid *state
WRITE32
(
OP_DELEGRETURN
);
WRITEMEM
(
stateid
->
data
,
NFS4_STATEID_SIZE
);
hdr
->
nops
++
;
hdr
->
replen
+=
decode_delegreturn_maxsz
;
}
#if defined(CONFIG_NFS_V4_1)
/* NFSv4.1 operations */
static
void
encode_exchange_id
(
struct
xdr_stream
*
xdr
,
struct
nfs41_exchange_id_args
*
args
,
struct
compound_hdr
*
hdr
)
{
__be32
*
p
;
RESERVE_SPACE
(
4
+
sizeof
(
args
->
verifier
->
data
));
WRITE32
(
OP_EXCHANGE_ID
);
WRITEMEM
(
args
->
verifier
->
data
,
sizeof
(
args
->
verifier
->
data
));
encode_string
(
xdr
,
args
->
id_len
,
args
->
id
);
RESERVE_SPACE
(
12
);
WRITE32
(
args
->
flags
);
WRITE32
(
0
);
/* zero length state_protect4_a */
WRITE32
(
0
);
/* zero length implementation id array */
hdr
->
nops
++
;
hdr
->
replen
+=
decode_exchange_id_maxsz
;
}
static
void
encode_create_session
(
struct
xdr_stream
*
xdr
,
struct
nfs41_create_session_args
*
args
,
struct
compound_hdr
*
hdr
)
{
__be32
*
p
;
char
machine_name
[
NFS4_MAX_MACHINE_NAME_LEN
];
uint32_t
len
;
struct
nfs_client
*
clp
=
args
->
client
;
RESERVE_SPACE
(
4
);
WRITE32
(
OP_CREATE_SESSION
);
RESERVE_SPACE
(
8
);
WRITE64
(
clp
->
cl_ex_clid
);
RESERVE_SPACE
(
8
);
WRITE32
(
clp
->
cl_seqid
);
/*Sequence id */
WRITE32
(
args
->
flags
);
/*flags */
RESERVE_SPACE
(
2
*
28
);
/* 2 channel_attrs */
/* Fore Channel */
WRITE32
(
args
->
fc_attrs
.
headerpadsz
);
/* header padding size */
WRITE32
(
args
->
fc_attrs
.
max_rqst_sz
);
/* max req size */
WRITE32
(
args
->
fc_attrs
.
max_resp_sz
);
/* max resp size */
WRITE32
(
args
->
fc_attrs
.
max_resp_sz_cached
);
/* Max resp sz cached */
WRITE32
(
args
->
fc_attrs
.
max_ops
);
/* max operations */
WRITE32
(
args
->
fc_attrs
.
max_reqs
);
/* max requests */
WRITE32
(
0
);
/* rdmachannel_attrs */
/* Back Channel */
WRITE32
(
args
->
fc_attrs
.
headerpadsz
);
/* header padding size */
WRITE32
(
args
->
bc_attrs
.
max_rqst_sz
);
/* max req size */
WRITE32
(
args
->
bc_attrs
.
max_resp_sz
);
/* max resp size */
WRITE32
(
args
->
bc_attrs
.
max_resp_sz_cached
);
/* Max resp sz cached */
WRITE32
(
args
->
bc_attrs
.
max_ops
);
/* max operations */
WRITE32
(
args
->
bc_attrs
.
max_reqs
);
/* max requests */
WRITE32
(
0
);
/* rdmachannel_attrs */
RESERVE_SPACE
(
4
);
WRITE32
(
args
->
cb_program
);
/* cb_program */
RESERVE_SPACE
(
4
);
/* # of security flavors */
WRITE32
(
1
);
RESERVE_SPACE
(
4
);
WRITE32
(
RPC_AUTH_UNIX
);
/* auth_sys */
/* authsys_parms rfc1831 */
RESERVE_SPACE
(
4
);
WRITE32
((
u32
)
clp
->
cl_boot_time
.
tv_nsec
);
/* stamp */
len
=
scnprintf
(
machine_name
,
sizeof
(
machine_name
),
"%s"
,
clp
->
cl_ipaddr
);
RESERVE_SPACE
(
16
+
len
);
WRITE32
(
len
);
WRITEMEM
(
machine_name
,
len
);
WRITE32
(
0
);
/* UID */
WRITE32
(
0
);
/* GID */
WRITE32
(
0
);
/* No more gids */
hdr
->
nops
++
;
hdr
->
replen
+=
decode_create_session_maxsz
;
}
static
void
encode_destroy_session
(
struct
xdr_stream
*
xdr
,
struct
nfs4_session
*
session
,
struct
compound_hdr
*
hdr
)
{
__be32
*
p
;
RESERVE_SPACE
(
4
+
NFS4_MAX_SESSIONID_LEN
);
WRITE32
(
OP_DESTROY_SESSION
);
WRITEMEM
(
session
->
sess_id
.
data
,
NFS4_MAX_SESSIONID_LEN
);
hdr
->
nops
++
;
hdr
->
replen
+=
decode_destroy_session_maxsz
;
}
#endif
/* CONFIG_NFS_V4_1 */
static
void
encode_sequence
(
struct
xdr_stream
*
xdr
,
const
struct
nfs4_sequence_args
*
args
,
struct
compound_hdr
*
hdr
)
{
#if defined(CONFIG_NFS_V4_1)
struct
nfs4_session
*
session
=
args
->
sa_session
;
struct
nfs4_slot_table
*
tp
;
struct
nfs4_slot
*
slot
;
__be32
*
p
;
if
(
!
session
)
return
;
tp
=
&
session
->
fc_slot_table
;
WARN_ON
(
args
->
sa_slotid
==
NFS4_MAX_SLOT_TABLE
);
slot
=
tp
->
slots
+
args
->
sa_slotid
;
RESERVE_SPACE
(
4
);
WRITE32
(
OP_SEQUENCE
);
/*
* Sessionid + seqid + slotid + max slotid + cache_this
*/
dprintk
(
"%s: sessionid=%u:%u:%u:%u seqid=%d slotid=%d "
"max_slotid=%d cache_this=%d
\n
"
,
__func__
,
((
u32
*
)
session
->
sess_id
.
data
)[
0
],
((
u32
*
)
session
->
sess_id
.
data
)[
1
],
((
u32
*
)
session
->
sess_id
.
data
)[
2
],
((
u32
*
)
session
->
sess_id
.
data
)[
3
],
slot
->
seq_nr
,
args
->
sa_slotid
,
tp
->
highest_used_slotid
,
args
->
sa_cache_this
);
RESERVE_SPACE
(
NFS4_MAX_SESSIONID_LEN
+
16
);
WRITEMEM
(
session
->
sess_id
.
data
,
NFS4_MAX_SESSIONID_LEN
);
WRITE32
(
slot
->
seq_nr
);
WRITE32
(
args
->
sa_slotid
);
WRITE32
(
tp
->
highest_used_slotid
);
WRITE32
(
args
->
sa_cache_this
);
hdr
->
nops
++
;
hdr
->
replen
+=
decode_sequence_maxsz
;
#endif
/* CONFIG_NFS_V4_1 */
}
/*
* END OF "GENERIC" ENCODE ROUTINES.
*/
static
u32
nfs4_xdr_minorversion
(
const
struct
nfs4_sequence_args
*
args
)
{
#if defined(CONFIG_NFS_V4_1)
if
(
args
->
sa_session
)
return
args
->
sa_session
->
clp
->
cl_minorversion
;
#endif
/* CONFIG_NFS_V4_1 */
return
0
;
}
/*
* Encode an ACCESS request
*/
...
...
@@ -1351,11 +1701,12 @@ static int nfs4_xdr_enc_access(struct rpc_rqst *req, __be32 *p, const struct nfs
{
struct
xdr_stream
xdr
;
struct
compound_hdr
hdr
=
{
.
nops
=
0
,
.
minorversion
=
nfs4_xdr_minorversion
(
&
args
->
seq_args
)
,
};
xdr_init_encode
(
&
xdr
,
&
req
->
rq_snd_buf
,
p
);
encode_compound_hdr
(
&
xdr
,
&
hdr
);
encode_compound_hdr
(
&
xdr
,
req
,
&
hdr
);
encode_sequence
(
&
xdr
,
&
args
->
seq_args
,
&
hdr
);
encode_putfh
(
&
xdr
,
args
->
fh
,
&
hdr
);
encode_access
(
&
xdr
,
args
->
access
,
&
hdr
);
encode_getfattr
(
&
xdr
,
args
->
bitmask
,
&
hdr
);
...
...
@@ -1370,11 +1721,12 @@ static int nfs4_xdr_enc_lookup(struct rpc_rqst *req, __be32 *p, const struct nfs
{
struct
xdr_stream
xdr
;
struct
compound_hdr
hdr
=
{
.
nops
=
0
,
.
minorversion
=
nfs4_xdr_minorversion
(
&
args
->
seq_args
)
,
};
xdr_init_encode
(
&
xdr
,
&
req
->
rq_snd_buf
,
p
);
encode_compound_hdr
(
&
xdr
,
&
hdr
);
encode_compound_hdr
(
&
xdr
,
req
,
&
hdr
);
encode_sequence
(
&
xdr
,
&
args
->
seq_args
,
&
hdr
);
encode_putfh
(
&
xdr
,
args
->
dir_fh
,
&
hdr
);
encode_lookup
(
&
xdr
,
args
->
name
,
&
hdr
);
encode_getfh
(
&
xdr
,
&
hdr
);
...
...
@@ -1390,11 +1742,12 @@ static int nfs4_xdr_enc_lookup_root(struct rpc_rqst *req, __be32 *p, const struc
{
struct
xdr_stream
xdr
;
struct
compound_hdr
hdr
=
{
.
nops
=
0
,
.
minorversion
=
nfs4_xdr_minorversion
(
&
args
->
seq_args
)
,
};
xdr_init_encode
(
&
xdr
,
&
req
->
rq_snd_buf
,
p
);
encode_compound_hdr
(
&
xdr
,
&
hdr
);
encode_compound_hdr
(
&
xdr
,
req
,
&
hdr
);
encode_sequence
(
&
xdr
,
&
args
->
seq_args
,
&
hdr
);
encode_putrootfh
(
&
xdr
,
&
hdr
);
encode_getfh
(
&
xdr
,
&
hdr
);
encode_getfattr
(
&
xdr
,
args
->
bitmask
,
&
hdr
);
...
...
@@ -1409,11 +1762,12 @@ static int nfs4_xdr_enc_remove(struct rpc_rqst *req, __be32 *p, const struct nfs
{
struct
xdr_stream
xdr
;
struct
compound_hdr
hdr
=
{
.
nops
=
0
,
.
minorversion
=
nfs4_xdr_minorversion
(
&
args
->
seq_args
)
,
};
xdr_init_encode
(
&
xdr
,
&
req
->
rq_snd_buf
,
p
);
encode_compound_hdr
(
&
xdr
,
&
hdr
);
encode_compound_hdr
(
&
xdr
,
req
,
&
hdr
);
encode_sequence
(
&
xdr
,
&
args
->
seq_args
,
&
hdr
);
encode_putfh
(
&
xdr
,
args
->
fh
,
&
hdr
);
encode_remove
(
&
xdr
,
&
args
->
name
,
&
hdr
);
encode_getfattr
(
&
xdr
,
args
->
bitmask
,
&
hdr
);
...
...
@@ -1428,11 +1782,12 @@ static int nfs4_xdr_enc_rename(struct rpc_rqst *req, __be32 *p, const struct nfs
{
struct
xdr_stream
xdr
;
struct
compound_hdr
hdr
=
{
.
nops
=
0
,
.
minorversion
=
nfs4_xdr_minorversion
(
&
args
->
seq_args
)
,
};
xdr_init_encode
(
&
xdr
,
&
req
->
rq_snd_buf
,
p
);
encode_compound_hdr
(
&
xdr
,
&
hdr
);
encode_compound_hdr
(
&
xdr
,
req
,
&
hdr
);
encode_sequence
(
&
xdr
,
&
args
->
seq_args
,
&
hdr
);
encode_putfh
(
&
xdr
,
args
->
old_dir
,
&
hdr
);
encode_savefh
(
&
xdr
,
&
hdr
);
encode_putfh
(
&
xdr
,
args
->
new_dir
,
&
hdr
);
...
...
@@ -1451,11 +1806,12 @@ static int nfs4_xdr_enc_link(struct rpc_rqst *req, __be32 *p, const struct nfs4_
{
struct
xdr_stream
xdr
;
struct
compound_hdr
hdr
=
{
.
nops
=
0
,
.
minorversion
=
nfs4_xdr_minorversion
(
&
args
->
seq_args
)
,
};
xdr_init_encode
(
&
xdr
,
&
req
->
rq_snd_buf
,
p
);
encode_compound_hdr
(
&
xdr
,
&
hdr
);
encode_compound_hdr
(
&
xdr
,
req
,
&
hdr
);
encode_sequence
(
&
xdr
,
&
args
->
seq_args
,
&
hdr
);
encode_putfh
(
&
xdr
,
args
->
fh
,
&
hdr
);
encode_savefh
(
&
xdr
,
&
hdr
);
encode_putfh
(
&
xdr
,
args
->
dir_fh
,
&
hdr
);
...
...
@@ -1474,11 +1830,12 @@ static int nfs4_xdr_enc_create(struct rpc_rqst *req, __be32 *p, const struct nfs
{
struct
xdr_stream
xdr
;
struct
compound_hdr
hdr
=
{
.
nops
=
0
,
.
minorversion
=
nfs4_xdr_minorversion
(
&
args
->
seq_args
)
,
};
xdr_init_encode
(
&
xdr
,
&
req
->
rq_snd_buf
,
p
);
encode_compound_hdr
(
&
xdr
,
&
hdr
);
encode_compound_hdr
(
&
xdr
,
req
,
&
hdr
);
encode_sequence
(
&
xdr
,
&
args
->
seq_args
,
&
hdr
);
encode_putfh
(
&
xdr
,
args
->
dir_fh
,
&
hdr
);
encode_savefh
(
&
xdr
,
&
hdr
);
encode_create
(
&
xdr
,
args
,
&
hdr
);
...
...
@@ -1505,11 +1862,12 @@ static int nfs4_xdr_enc_getattr(struct rpc_rqst *req, __be32 *p, const struct nf
{
struct
xdr_stream
xdr
;
struct
compound_hdr
hdr
=
{
.
nops
=
0
,
.
minorversion
=
nfs4_xdr_minorversion
(
&
args
->
seq_args
)
,
};
xdr_init_encode
(
&
xdr
,
&
req
->
rq_snd_buf
,
p
);
encode_compound_hdr
(
&
xdr
,
&
hdr
);
encode_compound_hdr
(
&
xdr
,
req
,
&
hdr
);
encode_sequence
(
&
xdr
,
&
args
->
seq_args
,
&
hdr
);
encode_putfh
(
&
xdr
,
args
->
fh
,
&
hdr
);
encode_getfattr
(
&
xdr
,
args
->
bitmask
,
&
hdr
);
encode_nops
(
&
hdr
);
...
...
@@ -1523,11 +1881,12 @@ static int nfs4_xdr_enc_close(struct rpc_rqst *req, __be32 *p, struct nfs_closea
{
struct
xdr_stream
xdr
;
struct
compound_hdr
hdr
=
{
.
nops
=
0
,
.
minorversion
=
nfs4_xdr_minorversion
(
&
args
->
seq_args
)
,
};
xdr_init_encode
(
&
xdr
,
&
req
->
rq_snd_buf
,
p
);
encode_compound_hdr
(
&
xdr
,
&
hdr
);
encode_compound_hdr
(
&
xdr
,
req
,
&
hdr
);
encode_sequence
(
&
xdr
,
&
args
->
seq_args
,
&
hdr
);
encode_putfh
(
&
xdr
,
args
->
fh
,
&
hdr
);
encode_close
(
&
xdr
,
args
,
&
hdr
);
encode_getfattr
(
&
xdr
,
args
->
bitmask
,
&
hdr
);
...
...
@@ -1542,11 +1901,12 @@ static int nfs4_xdr_enc_open(struct rpc_rqst *req, __be32 *p, struct nfs_openarg
{
struct
xdr_stream
xdr
;
struct
compound_hdr
hdr
=
{
.
nops
=
0
,
.
minorversion
=
nfs4_xdr_minorversion
(
&
args
->
seq_args
)
,
};
xdr_init_encode
(
&
xdr
,
&
req
->
rq_snd_buf
,
p
);
encode_compound_hdr
(
&
xdr
,
&
hdr
);
encode_compound_hdr
(
&
xdr
,
req
,
&
hdr
);
encode_sequence
(
&
xdr
,
&
args
->
seq_args
,
&
hdr
);
encode_putfh
(
&
xdr
,
args
->
fh
,
&
hdr
);
encode_savefh
(
&
xdr
,
&
hdr
);
encode_open
(
&
xdr
,
args
,
&
hdr
);
...
...
@@ -1569,7 +1929,7 @@ static int nfs4_xdr_enc_open_confirm(struct rpc_rqst *req, __be32 *p, struct nfs
};
xdr_init_encode
(
&
xdr
,
&
req
->
rq_snd_buf
,
p
);
encode_compound_hdr
(
&
xdr
,
&
hdr
);
encode_compound_hdr
(
&
xdr
,
req
,
&
hdr
);
encode_putfh
(
&
xdr
,
args
->
fh
,
&
hdr
);
encode_open_confirm
(
&
xdr
,
args
,
&
hdr
);
encode_nops
(
&
hdr
);
...
...
@@ -1583,11 +1943,12 @@ static int nfs4_xdr_enc_open_noattr(struct rpc_rqst *req, __be32 *p, struct nfs_
{
struct
xdr_stream
xdr
;
struct
compound_hdr
hdr
=
{
.
nops
=
0
,
.
minorversion
=
nfs4_xdr_minorversion
(
&
args
->
seq_args
)
,
};
xdr_init_encode
(
&
xdr
,
&
req
->
rq_snd_buf
,
p
);
encode_compound_hdr
(
&
xdr
,
&
hdr
);
encode_compound_hdr
(
&
xdr
,
req
,
&
hdr
);
encode_sequence
(
&
xdr
,
&
args
->
seq_args
,
&
hdr
);
encode_putfh
(
&
xdr
,
args
->
fh
,
&
hdr
);
encode_open
(
&
xdr
,
args
,
&
hdr
);
encode_getfattr
(
&
xdr
,
args
->
bitmask
,
&
hdr
);
...
...
@@ -1602,11 +1963,12 @@ static int nfs4_xdr_enc_open_downgrade(struct rpc_rqst *req, __be32 *p, struct n
{
struct
xdr_stream
xdr
;
struct
compound_hdr
hdr
=
{
.
nops
=
0
,
.
minorversion
=
nfs4_xdr_minorversion
(
&
args
->
seq_args
)
,
};
xdr_init_encode
(
&
xdr
,
&
req
->
rq_snd_buf
,
p
);
encode_compound_hdr
(
&
xdr
,
&
hdr
);
encode_compound_hdr
(
&
xdr
,
req
,
&
hdr
);
encode_sequence
(
&
xdr
,
&
args
->
seq_args
,
&
hdr
);
encode_putfh
(
&
xdr
,
args
->
fh
,
&
hdr
);
encode_open_downgrade
(
&
xdr
,
args
,
&
hdr
);
encode_getfattr
(
&
xdr
,
args
->
bitmask
,
&
hdr
);
...
...
@@ -1621,11 +1983,12 @@ static int nfs4_xdr_enc_lock(struct rpc_rqst *req, __be32 *p, struct nfs_lock_ar
{
struct
xdr_stream
xdr
;
struct
compound_hdr
hdr
=
{
.
nops
=
0
,
.
minorversion
=
nfs4_xdr_minorversion
(
&
args
->
seq_args
)
,
};
xdr_init_encode
(
&
xdr
,
&
req
->
rq_snd_buf
,
p
);
encode_compound_hdr
(
&
xdr
,
&
hdr
);
encode_compound_hdr
(
&
xdr
,
req
,
&
hdr
);
encode_sequence
(
&
xdr
,
&
args
->
seq_args
,
&
hdr
);
encode_putfh
(
&
xdr
,
args
->
fh
,
&
hdr
);
encode_lock
(
&
xdr
,
args
,
&
hdr
);
encode_nops
(
&
hdr
);
...
...
@@ -1639,11 +2002,12 @@ static int nfs4_xdr_enc_lockt(struct rpc_rqst *req, __be32 *p, struct nfs_lockt_
{
struct
xdr_stream
xdr
;
struct
compound_hdr
hdr
=
{
.
nops
=
0
,
.
minorversion
=
nfs4_xdr_minorversion
(
&
args
->
seq_args
)
,
};
xdr_init_encode
(
&
xdr
,
&
req
->
rq_snd_buf
,
p
);
encode_compound_hdr
(
&
xdr
,
&
hdr
);
encode_compound_hdr
(
&
xdr
,
req
,
&
hdr
);
encode_sequence
(
&
xdr
,
&
args
->
seq_args
,
&
hdr
);
encode_putfh
(
&
xdr
,
args
->
fh
,
&
hdr
);
encode_lockt
(
&
xdr
,
args
,
&
hdr
);
encode_nops
(
&
hdr
);
...
...
@@ -1657,11 +2021,12 @@ static int nfs4_xdr_enc_locku(struct rpc_rqst *req, __be32 *p, struct nfs_locku_
{
struct
xdr_stream
xdr
;
struct
compound_hdr
hdr
=
{
.
nops
=
0
,
.
minorversion
=
nfs4_xdr_minorversion
(
&
args
->
seq_args
)
,
};
xdr_init_encode
(
&
xdr
,
&
req
->
rq_snd_buf
,
p
);
encode_compound_hdr
(
&
xdr
,
&
hdr
);
encode_compound_hdr
(
&
xdr
,
req
,
&
hdr
);
encode_sequence
(
&
xdr
,
&
args
->
seq_args
,
&
hdr
);
encode_putfh
(
&
xdr
,
args
->
fh
,
&
hdr
);
encode_locku
(
&
xdr
,
args
,
&
hdr
);
encode_nops
(
&
hdr
);
...
...
@@ -1675,22 +2040,16 @@ static int nfs4_xdr_enc_readlink(struct rpc_rqst *req, __be32 *p, const struct n
{
struct
xdr_stream
xdr
;
struct
compound_hdr
hdr
=
{
.
nops
=
0
,
.
minorversion
=
nfs4_xdr_minorversion
(
&
args
->
seq_args
)
,
};
struct
rpc_auth
*
auth
=
req
->
rq_task
->
tk_msg
.
rpc_cred
->
cr_auth
;
unsigned
int
replen
;
xdr_init_encode
(
&
xdr
,
&
req
->
rq_snd_buf
,
p
);
encode_compound_hdr
(
&
xdr
,
&
hdr
);
encode_compound_hdr
(
&
xdr
,
req
,
&
hdr
);
encode_sequence
(
&
xdr
,
&
args
->
seq_args
,
&
hdr
);
encode_putfh
(
&
xdr
,
args
->
fh
,
&
hdr
);
encode_readlink
(
&
xdr
,
args
,
req
,
&
hdr
);
/* set up reply kvec
* toplevel_status + taglen + rescount + OP_PUTFH + status
* + OP_READLINK + status + string length = 8
*/
replen
=
(
RPC_REPHDRSIZE
+
auth
->
au_rslack
+
NFS4_dec_readlink_sz
)
<<
2
;
xdr_inline_pages
(
&
req
->
rq_rcv_buf
,
replen
,
args
->
pages
,
xdr_inline_pages
(
&
req
->
rq_rcv_buf
,
hdr
.
replen
<<
2
,
args
->
pages
,
args
->
pgbase
,
args
->
pglen
);
encode_nops
(
&
hdr
);
return
0
;
...
...
@@ -1703,25 +2062,19 @@ static int nfs4_xdr_enc_readdir(struct rpc_rqst *req, __be32 *p, const struct nf
{
struct
xdr_stream
xdr
;
struct
compound_hdr
hdr
=
{
.
nops
=
0
,
.
minorversion
=
nfs4_xdr_minorversion
(
&
args
->
seq_args
)
,
};
struct
rpc_auth
*
auth
=
req
->
rq_task
->
tk_msg
.
rpc_cred
->
cr_auth
;
int
replen
;
xdr_init_encode
(
&
xdr
,
&
req
->
rq_snd_buf
,
p
);
encode_compound_hdr
(
&
xdr
,
&
hdr
);
encode_compound_hdr
(
&
xdr
,
req
,
&
hdr
);
encode_sequence
(
&
xdr
,
&
args
->
seq_args
,
&
hdr
);
encode_putfh
(
&
xdr
,
args
->
fh
,
&
hdr
);
encode_readdir
(
&
xdr
,
args
,
req
,
&
hdr
);
/* set up reply kvec
* toplevel_status + taglen + rescount + OP_PUTFH + status
* + OP_READDIR + status + verifer(2) = 9
*/
replen
=
(
RPC_REPHDRSIZE
+
auth
->
au_rslack
+
NFS4_dec_readdir_sz
)
<<
2
;
xdr_inline_pages
(
&
req
->
rq_rcv_buf
,
replen
,
args
->
pages
,
xdr_inline_pages
(
&
req
->
rq_rcv_buf
,
hdr
.
replen
<<
2
,
args
->
pages
,
args
->
pgbase
,
args
->
count
);
dprintk
(
"%s: inlined page args = (%u, %p, %u, %u)
\n
"
,
__func__
,
replen
,
args
->
pages
,
__func__
,
hdr
.
replen
<<
2
,
args
->
pages
,
args
->
pgbase
,
args
->
count
);
encode_nops
(
&
hdr
);
return
0
;
...
...
@@ -1732,24 +2085,18 @@ static int nfs4_xdr_enc_readdir(struct rpc_rqst *req, __be32 *p, const struct nf
*/
static
int
nfs4_xdr_enc_read
(
struct
rpc_rqst
*
req
,
__be32
*
p
,
struct
nfs_readargs
*
args
)
{
struct
rpc_auth
*
auth
=
req
->
rq_task
->
tk_msg
.
rpc_cred
->
cr_auth
;
struct
xdr_stream
xdr
;
struct
compound_hdr
hdr
=
{
.
nops
=
0
,
.
minorversion
=
nfs4_xdr_minorversion
(
&
args
->
seq_args
)
,
};
int
replen
;
xdr_init_encode
(
&
xdr
,
&
req
->
rq_snd_buf
,
p
);
encode_compound_hdr
(
&
xdr
,
&
hdr
);
encode_compound_hdr
(
&
xdr
,
req
,
&
hdr
);
encode_sequence
(
&
xdr
,
&
args
->
seq_args
,
&
hdr
);
encode_putfh
(
&
xdr
,
args
->
fh
,
&
hdr
);
encode_read
(
&
xdr
,
args
,
&
hdr
);
/* set up reply kvec
* toplevel status + taglen=0 + rescount + OP_PUTFH + status
* + OP_READ + status + eof + datalen = 9
*/
replen
=
(
RPC_REPHDRSIZE
+
auth
->
au_rslack
+
NFS4_dec_read_sz
)
<<
2
;
xdr_inline_pages
(
&
req
->
rq_rcv_buf
,
replen
,
xdr_inline_pages
(
&
req
->
rq_rcv_buf
,
hdr
.
replen
<<
2
,
args
->
pages
,
args
->
pgbase
,
args
->
count
);
req
->
rq_rcv_buf
.
flags
|=
XDRBUF_READ
;
encode_nops
(
&
hdr
);
...
...
@@ -1763,11 +2110,12 @@ static int nfs4_xdr_enc_setattr(struct rpc_rqst *req, __be32 *p, struct nfs_seta
{
struct
xdr_stream
xdr
;
struct
compound_hdr
hdr
=
{
.
nops
=
0
,
.
minorversion
=
nfs4_xdr_minorversion
(
&
args
->
seq_args
)
,
};
xdr_init_encode
(
&
xdr
,
&
req
->
rq_snd_buf
,
p
);
encode_compound_hdr
(
&
xdr
,
&
hdr
);
encode_compound_hdr
(
&
xdr
,
req
,
&
hdr
);
encode_sequence
(
&
xdr
,
&
args
->
seq_args
,
&
hdr
);
encode_putfh
(
&
xdr
,
args
->
fh
,
&
hdr
);
encode_setattr
(
&
xdr
,
args
,
args
->
server
,
&
hdr
);
encode_getfattr
(
&
xdr
,
args
->
bitmask
,
&
hdr
);
...
...
@@ -1783,20 +2131,19 @@ nfs4_xdr_enc_getacl(struct rpc_rqst *req, __be32 *p,
struct
nfs_getaclargs
*
args
)
{
struct
xdr_stream
xdr
;
struct
rpc_auth
*
auth
=
req
->
rq_task
->
tk_msg
.
rpc_cred
->
cr_auth
;
struct
compound_hdr
hdr
=
{
.
nops
=
0
,
.
minorversion
=
nfs4_xdr_minorversion
(
&
args
->
seq_args
)
,
};
in
t
replen
;
uint32_
t
replen
;
xdr_init_encode
(
&
xdr
,
&
req
->
rq_snd_buf
,
p
);
encode_compound_hdr
(
&
xdr
,
&
hdr
);
encode_compound_hdr
(
&
xdr
,
req
,
&
hdr
);
encode_sequence
(
&
xdr
,
&
args
->
seq_args
,
&
hdr
);
encode_putfh
(
&
xdr
,
args
->
fh
,
&
hdr
);
replen
=
hdr
.
replen
+
nfs4_fattr_bitmap_maxsz
+
1
;
encode_getattr_two
(
&
xdr
,
FATTR4_WORD0_ACL
,
0
,
&
hdr
);
/* set up reply buffer: */
replen
=
(
RPC_REPHDRSIZE
+
auth
->
au_rslack
+
NFS4_dec_getacl_sz
)
<<
2
;
xdr_inline_pages
(
&
req
->
rq_rcv_buf
,
replen
,
xdr_inline_pages
(
&
req
->
rq_rcv_buf
,
replen
<<
2
,
args
->
acl_pages
,
args
->
acl_pgbase
,
args
->
acl_len
);
encode_nops
(
&
hdr
);
return
0
;
...
...
@@ -1809,11 +2156,12 @@ static int nfs4_xdr_enc_write(struct rpc_rqst *req, __be32 *p, struct nfs_writea
{
struct
xdr_stream
xdr
;
struct
compound_hdr
hdr
=
{
.
nops
=
0
,
.
minorversion
=
nfs4_xdr_minorversion
(
&
args
->
seq_args
)
,
};
xdr_init_encode
(
&
xdr
,
&
req
->
rq_snd_buf
,
p
);
encode_compound_hdr
(
&
xdr
,
&
hdr
);
encode_compound_hdr
(
&
xdr
,
req
,
&
hdr
);
encode_sequence
(
&
xdr
,
&
args
->
seq_args
,
&
hdr
);
encode_putfh
(
&
xdr
,
args
->
fh
,
&
hdr
);
encode_write
(
&
xdr
,
args
,
&
hdr
);
req
->
rq_snd_buf
.
flags
|=
XDRBUF_WRITE
;
...
...
@@ -1829,11 +2177,12 @@ static int nfs4_xdr_enc_commit(struct rpc_rqst *req, __be32 *p, struct nfs_write
{
struct
xdr_stream
xdr
;
struct
compound_hdr
hdr
=
{
.
nops
=
0
,
.
minorversion
=
nfs4_xdr_minorversion
(
&
args
->
seq_args
)
,
};
xdr_init_encode
(
&
xdr
,
&
req
->
rq_snd_buf
,
p
);
encode_compound_hdr
(
&
xdr
,
&
hdr
);
encode_compound_hdr
(
&
xdr
,
req
,
&
hdr
);
encode_sequence
(
&
xdr
,
&
args
->
seq_args
,
&
hdr
);
encode_putfh
(
&
xdr
,
args
->
fh
,
&
hdr
);
encode_commit
(
&
xdr
,
args
,
&
hdr
);
encode_getfattr
(
&
xdr
,
args
->
bitmask
,
&
hdr
);
...
...
@@ -1848,11 +2197,12 @@ static int nfs4_xdr_enc_fsinfo(struct rpc_rqst *req, __be32 *p, struct nfs4_fsin
{
struct
xdr_stream
xdr
;
struct
compound_hdr
hdr
=
{
.
nops
=
0
,
.
minorversion
=
nfs4_xdr_minorversion
(
&
args
->
seq_args
)
,
};
xdr_init_encode
(
&
xdr
,
&
req
->
rq_snd_buf
,
p
);
encode_compound_hdr
(
&
xdr
,
&
hdr
);
encode_compound_hdr
(
&
xdr
,
req
,
&
hdr
);
encode_sequence
(
&
xdr
,
&
args
->
seq_args
,
&
hdr
);
encode_putfh
(
&
xdr
,
args
->
fh
,
&
hdr
);
encode_fsinfo
(
&
xdr
,
args
->
bitmask
,
&
hdr
);
encode_nops
(
&
hdr
);
...
...
@@ -1866,11 +2216,12 @@ static int nfs4_xdr_enc_pathconf(struct rpc_rqst *req, __be32 *p, const struct n
{
struct
xdr_stream
xdr
;
struct
compound_hdr
hdr
=
{
.
nops
=
0
,
.
minorversion
=
nfs4_xdr_minorversion
(
&
args
->
seq_args
)
,
};
xdr_init_encode
(
&
xdr
,
&
req
->
rq_snd_buf
,
p
);
encode_compound_hdr
(
&
xdr
,
&
hdr
);
encode_compound_hdr
(
&
xdr
,
req
,
&
hdr
);
encode_sequence
(
&
xdr
,
&
args
->
seq_args
,
&
hdr
);
encode_putfh
(
&
xdr
,
args
->
fh
,
&
hdr
);
encode_getattr_one
(
&
xdr
,
args
->
bitmask
[
0
]
&
nfs4_pathconf_bitmap
[
0
],
&
hdr
);
...
...
@@ -1885,11 +2236,12 @@ static int nfs4_xdr_enc_statfs(struct rpc_rqst *req, __be32 *p, const struct nfs
{
struct
xdr_stream
xdr
;
struct
compound_hdr
hdr
=
{
.
nops
=
0
,
.
minorversion
=
nfs4_xdr_minorversion
(
&
args
->
seq_args
)
,
};
xdr_init_encode
(
&
xdr
,
&
req
->
rq_snd_buf
,
p
);
encode_compound_hdr
(
&
xdr
,
&
hdr
);
encode_compound_hdr
(
&
xdr
,
req
,
&
hdr
);
encode_sequence
(
&
xdr
,
&
args
->
seq_args
,
&
hdr
);
encode_putfh
(
&
xdr
,
args
->
fh
,
&
hdr
);
encode_getattr_two
(
&
xdr
,
args
->
bitmask
[
0
]
&
nfs4_statfs_bitmap
[
0
],
args
->
bitmask
[
1
]
&
nfs4_statfs_bitmap
[
1
],
&
hdr
);
...
...
@@ -1900,16 +2252,18 @@ static int nfs4_xdr_enc_statfs(struct rpc_rqst *req, __be32 *p, const struct nfs
/*
* GETATTR_BITMAP request
*/
static
int
nfs4_xdr_enc_server_caps
(
struct
rpc_rqst
*
req
,
__be32
*
p
,
const
struct
nfs_fh
*
fhandle
)
static
int
nfs4_xdr_enc_server_caps
(
struct
rpc_rqst
*
req
,
__be32
*
p
,
struct
nfs4_server_caps_arg
*
args
)
{
struct
xdr_stream
xdr
;
struct
compound_hdr
hdr
=
{
.
nops
=
0
,
.
minorversion
=
nfs4_xdr_minorversion
(
&
args
->
seq_args
)
,
};
xdr_init_encode
(
&
xdr
,
&
req
->
rq_snd_buf
,
p
);
encode_compound_hdr
(
&
xdr
,
&
hdr
);
encode_putfh
(
&
xdr
,
fhandle
,
&
hdr
);
encode_compound_hdr
(
&
xdr
,
req
,
&
hdr
);
encode_sequence
(
&
xdr
,
&
args
->
seq_args
,
&
hdr
);
encode_putfh
(
&
xdr
,
args
->
fhandle
,
&
hdr
);
encode_getattr_one
(
&
xdr
,
FATTR4_WORD0_SUPPORTED_ATTRS
|
FATTR4_WORD0_LINK_SUPPORT
|
FATTR4_WORD0_SYMLINK_SUPPORT
|
...
...
@@ -1929,7 +2283,7 @@ static int nfs4_xdr_enc_renew(struct rpc_rqst *req, __be32 *p, struct nfs_client
};
xdr_init_encode
(
&
xdr
,
&
req
->
rq_snd_buf
,
p
);
encode_compound_hdr
(
&
xdr
,
&
hdr
);
encode_compound_hdr
(
&
xdr
,
req
,
&
hdr
);
encode_renew
(
&
xdr
,
clp
,
&
hdr
);
encode_nops
(
&
hdr
);
return
0
;
...
...
@@ -1946,7 +2300,7 @@ static int nfs4_xdr_enc_setclientid(struct rpc_rqst *req, __be32 *p, struct nfs4
};
xdr_init_encode
(
&
xdr
,
&
req
->
rq_snd_buf
,
p
);
encode_compound_hdr
(
&
xdr
,
&
hdr
);
encode_compound_hdr
(
&
xdr
,
req
,
&
hdr
);
encode_setclientid
(
&
xdr
,
sc
,
&
hdr
);
encode_nops
(
&
hdr
);
return
0
;
...
...
@@ -1964,7 +2318,7 @@ static int nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req, __be32 *p, str
const
u32
lease_bitmap
[
2
]
=
{
FATTR4_WORD0_LEASE_TIME
,
0
};
xdr_init_encode
(
&
xdr
,
&
req
->
rq_snd_buf
,
p
);
encode_compound_hdr
(
&
xdr
,
&
hdr
);
encode_compound_hdr
(
&
xdr
,
req
,
&
hdr
);
encode_setclientid_confirm
(
&
xdr
,
clp
,
&
hdr
);
encode_putrootfh
(
&
xdr
,
&
hdr
);
encode_fsinfo
(
&
xdr
,
lease_bitmap
,
&
hdr
);
...
...
@@ -1979,11 +2333,12 @@ static int nfs4_xdr_enc_delegreturn(struct rpc_rqst *req, __be32 *p, const struc
{
struct
xdr_stream
xdr
;
struct
compound_hdr
hdr
=
{
.
nops
=
0
,
.
minorversion
=
nfs4_xdr_minorversion
(
&
args
->
seq_args
)
,
};
xdr_init_encode
(
&
xdr
,
&
req
->
rq_snd_buf
,
p
);
encode_compound_hdr
(
&
xdr
,
&
hdr
);
encode_compound_hdr
(
&
xdr
,
req
,
&
hdr
);
encode_sequence
(
&
xdr
,
&
args
->
seq_args
,
&
hdr
);
encode_putfh
(
&
xdr
,
args
->
fhandle
,
&
hdr
);
encode_delegreturn
(
&
xdr
,
args
->
stateid
,
&
hdr
);
encode_getfattr
(
&
xdr
,
args
->
bitmask
,
&
hdr
);
...
...
@@ -1998,28 +2353,119 @@ static int nfs4_xdr_enc_fs_locations(struct rpc_rqst *req, __be32 *p, struct nfs
{
struct
xdr_stream
xdr
;
struct
compound_hdr
hdr
=
{
.
nops
=
0
,
.
minorversion
=
nfs4_xdr_minorversion
(
&
args
->
seq_args
)
,
};
struct
rpc_auth
*
auth
=
req
->
rq_task
->
tk_msg
.
rpc_cred
->
cr_auth
;
int
replen
;
uint32_t
replen
;
xdr_init_encode
(
&
xdr
,
&
req
->
rq_snd_buf
,
p
);
encode_compound_hdr
(
&
xdr
,
&
hdr
);
encode_compound_hdr
(
&
xdr
,
req
,
&
hdr
);
encode_sequence
(
&
xdr
,
&
args
->
seq_args
,
&
hdr
);
encode_putfh
(
&
xdr
,
args
->
dir_fh
,
&
hdr
);
encode_lookup
(
&
xdr
,
args
->
name
,
&
hdr
);
replen
=
hdr
.
replen
;
/* get the attribute into args->page */
encode_fs_locations
(
&
xdr
,
args
->
bitmask
,
&
hdr
);
/* set up reply
* toplevel_status + OP_PUTFH + status
* + OP_LOOKUP + status + OP_GETATTR + status = 7
*/
replen
=
(
RPC_REPHDRSIZE
+
auth
->
au_rslack
+
7
)
<<
2
;
xdr_inline_pages
(
&
req
->
rq_rcv_buf
,
replen
,
&
args
->
page
,
xdr_inline_pages
(
&
req
->
rq_rcv_buf
,
replen
<<
2
,
&
args
->
page
,
0
,
PAGE_SIZE
);
encode_nops
(
&
hdr
);
return
0
;
}
#if defined(CONFIG_NFS_V4_1)
/*
* EXCHANGE_ID request
*/
static
int
nfs4_xdr_enc_exchange_id
(
struct
rpc_rqst
*
req
,
uint32_t
*
p
,
struct
nfs41_exchange_id_args
*
args
)
{
struct
xdr_stream
xdr
;
struct
compound_hdr
hdr
=
{
.
minorversion
=
args
->
client
->
cl_minorversion
,
};
xdr_init_encode
(
&
xdr
,
&
req
->
rq_snd_buf
,
p
);
encode_compound_hdr
(
&
xdr
,
req
,
&
hdr
);
encode_exchange_id
(
&
xdr
,
args
,
&
hdr
);
encode_nops
(
&
hdr
);
return
0
;
}
/*
* a CREATE_SESSION request
*/
static
int
nfs4_xdr_enc_create_session
(
struct
rpc_rqst
*
req
,
uint32_t
*
p
,
struct
nfs41_create_session_args
*
args
)
{
struct
xdr_stream
xdr
;
struct
compound_hdr
hdr
=
{
.
minorversion
=
args
->
client
->
cl_minorversion
,
};
xdr_init_encode
(
&
xdr
,
&
req
->
rq_snd_buf
,
p
);
encode_compound_hdr
(
&
xdr
,
req
,
&
hdr
);
encode_create_session
(
&
xdr
,
args
,
&
hdr
);
encode_nops
(
&
hdr
);
return
0
;
}
/*
* a DESTROY_SESSION request
*/
static
int
nfs4_xdr_enc_destroy_session
(
struct
rpc_rqst
*
req
,
uint32_t
*
p
,
struct
nfs4_session
*
session
)
{
struct
xdr_stream
xdr
;
struct
compound_hdr
hdr
=
{
.
minorversion
=
session
->
clp
->
cl_minorversion
,
};
xdr_init_encode
(
&
xdr
,
&
req
->
rq_snd_buf
,
p
);
encode_compound_hdr
(
&
xdr
,
req
,
&
hdr
);
encode_destroy_session
(
&
xdr
,
session
,
&
hdr
);
encode_nops
(
&
hdr
);
return
0
;
}
/*
* a SEQUENCE request
*/
static
int
nfs4_xdr_enc_sequence
(
struct
rpc_rqst
*
req
,
uint32_t
*
p
,
struct
nfs4_sequence_args
*
args
)
{
struct
xdr_stream
xdr
;
struct
compound_hdr
hdr
=
{
.
minorversion
=
nfs4_xdr_minorversion
(
args
),
};
xdr_init_encode
(
&
xdr
,
&
req
->
rq_snd_buf
,
p
);
encode_compound_hdr
(
&
xdr
,
req
,
&
hdr
);
encode_sequence
(
&
xdr
,
args
,
&
hdr
);
encode_nops
(
&
hdr
);
return
0
;
}
/*
* a GET_LEASE_TIME request
*/
static
int
nfs4_xdr_enc_get_lease_time
(
struct
rpc_rqst
*
req
,
uint32_t
*
p
,
struct
nfs4_get_lease_time_args
*
args
)
{
struct
xdr_stream
xdr
;
struct
compound_hdr
hdr
=
{
.
minorversion
=
nfs4_xdr_minorversion
(
&
args
->
la_seq_args
),
};
const
u32
lease_bitmap
[
2
]
=
{
FATTR4_WORD0_LEASE_TIME
,
0
};
xdr_init_encode
(
&
xdr
,
&
req
->
rq_snd_buf
,
p
);
encode_compound_hdr
(
&
xdr
,
req
,
&
hdr
);
encode_sequence
(
&
xdr
,
&
args
->
la_seq_args
,
&
hdr
);
encode_putrootfh
(
&
xdr
,
&
hdr
);
encode_fsinfo
(
&
xdr
,
lease_bitmap
,
&
hdr
);
encode_nops
(
&
hdr
);
return
0
;
}
#endif
/* CONFIG_NFS_V4_1 */
/*
* START OF "GENERIC" DECODE ROUTINES.
* These may look a little ugly since they are imported from a "generic"
...
...
@@ -3657,7 +4103,7 @@ decode_savefh(struct xdr_stream *xdr)
return
decode_op_hdr
(
xdr
,
OP_SAVEFH
);
}
static
int
decode_setattr
(
struct
xdr_stream
*
xdr
,
struct
nfs_setattrres
*
res
)
static
int
decode_setattr
(
struct
xdr_stream
*
xdr
)
{
__be32
*
p
;
uint32_t
bmlen
;
...
...
@@ -3735,6 +4181,169 @@ static int decode_delegreturn(struct xdr_stream *xdr)
return
decode_op_hdr
(
xdr
,
OP_DELEGRETURN
);
}
#if defined(CONFIG_NFS_V4_1)
static
int
decode_exchange_id
(
struct
xdr_stream
*
xdr
,
struct
nfs41_exchange_id_res
*
res
)
{
__be32
*
p
;
uint32_t
dummy
;
int
status
;
struct
nfs_client
*
clp
=
res
->
client
;
status
=
decode_op_hdr
(
xdr
,
OP_EXCHANGE_ID
);
if
(
status
)
return
status
;
READ_BUF
(
8
);
READ64
(
clp
->
cl_ex_clid
);
READ_BUF
(
12
);
READ32
(
clp
->
cl_seqid
);
READ32
(
clp
->
cl_exchange_flags
);
/* We ask for SP4_NONE */
READ32
(
dummy
);
if
(
dummy
!=
SP4_NONE
)
return
-
EIO
;
/* Throw away minor_id */
READ_BUF
(
8
);
/* Throw away Major id */
READ_BUF
(
4
);
READ32
(
dummy
);
READ_BUF
(
dummy
);
/* Throw away server_scope */
READ_BUF
(
4
);
READ32
(
dummy
);
READ_BUF
(
dummy
);
/* Throw away Implementation id array */
READ_BUF
(
4
);
READ32
(
dummy
);
READ_BUF
(
dummy
);
return
0
;
}
static
int
decode_chan_attrs
(
struct
xdr_stream
*
xdr
,
struct
nfs4_channel_attrs
*
attrs
)
{
__be32
*
p
;
u32
nr_attrs
;
READ_BUF
(
28
);
READ32
(
attrs
->
headerpadsz
);
READ32
(
attrs
->
max_rqst_sz
);
READ32
(
attrs
->
max_resp_sz
);
READ32
(
attrs
->
max_resp_sz_cached
);
READ32
(
attrs
->
max_ops
);
READ32
(
attrs
->
max_reqs
);
READ32
(
nr_attrs
);
if
(
unlikely
(
nr_attrs
>
1
))
{
printk
(
KERN_WARNING
"%s: Invalid rdma channel attrs count %u
\n
"
,
__func__
,
nr_attrs
);
return
-
EINVAL
;
}
if
(
nr_attrs
==
1
)
READ_BUF
(
4
);
/* skip rdma_attrs */
return
0
;
}
static
int
decode_create_session
(
struct
xdr_stream
*
xdr
,
struct
nfs41_create_session_res
*
res
)
{
__be32
*
p
;
int
status
;
struct
nfs_client
*
clp
=
res
->
client
;
struct
nfs4_session
*
session
=
clp
->
cl_session
;
status
=
decode_op_hdr
(
xdr
,
OP_CREATE_SESSION
);
if
(
status
)
return
status
;
/* sessionid */
READ_BUF
(
NFS4_MAX_SESSIONID_LEN
);
COPYMEM
(
&
session
->
sess_id
,
NFS4_MAX_SESSIONID_LEN
);
/* seqid, flags */
READ_BUF
(
8
);
READ32
(
clp
->
cl_seqid
);
READ32
(
session
->
flags
);
/* Channel attributes */
status
=
decode_chan_attrs
(
xdr
,
&
session
->
fc_attrs
);
if
(
!
status
)
status
=
decode_chan_attrs
(
xdr
,
&
session
->
bc_attrs
);
return
status
;
}
static
int
decode_destroy_session
(
struct
xdr_stream
*
xdr
,
void
*
dummy
)
{
return
decode_op_hdr
(
xdr
,
OP_DESTROY_SESSION
);
}
#endif
/* CONFIG_NFS_V4_1 */
static
int
decode_sequence
(
struct
xdr_stream
*
xdr
,
struct
nfs4_sequence_res
*
res
,
struct
rpc_rqst
*
rqstp
)
{
#if defined(CONFIG_NFS_V4_1)
struct
nfs4_slot
*
slot
;
struct
nfs4_sessionid
id
;
u32
dummy
;
int
status
;
__be32
*
p
;
if
(
!
res
->
sr_session
)
return
0
;
status
=
decode_op_hdr
(
xdr
,
OP_SEQUENCE
);
if
(
status
)
goto
out_err
;
/*
* If the server returns different values for sessionID, slotID or
* sequence number, the server is looney tunes.
*/
status
=
-
ESERVERFAULT
;
slot
=
&
res
->
sr_session
->
fc_slot_table
.
slots
[
res
->
sr_slotid
];
READ_BUF
(
NFS4_MAX_SESSIONID_LEN
+
20
);
COPYMEM
(
id
.
data
,
NFS4_MAX_SESSIONID_LEN
);
if
(
memcmp
(
id
.
data
,
res
->
sr_session
->
sess_id
.
data
,
NFS4_MAX_SESSIONID_LEN
))
{
dprintk
(
"%s Invalid session id
\n
"
,
__func__
);
goto
out_err
;
}
/* seqid */
READ32
(
dummy
);
if
(
dummy
!=
slot
->
seq_nr
)
{
dprintk
(
"%s Invalid sequence number
\n
"
,
__func__
);
goto
out_err
;
}
/* slot id */
READ32
(
dummy
);
if
(
dummy
!=
res
->
sr_slotid
)
{
dprintk
(
"%s Invalid slot id
\n
"
,
__func__
);
goto
out_err
;
}
/* highest slot id - currently not processed */
READ32
(
dummy
);
/* target highest slot id - currently not processed */
READ32
(
dummy
);
/* result flags - currently not processed */
READ32
(
dummy
);
status
=
0
;
out_err:
res
->
sr_status
=
status
;
return
status
;
#else
/* CONFIG_NFS_V4_1 */
return
0
;
#endif
/* CONFIG_NFS_V4_1 */
}
/*
* END OF "GENERIC" DECODE ROUTINES.
*/
...
...
@@ -3750,6 +4359,9 @@ static int nfs4_xdr_dec_open_downgrade(struct rpc_rqst *rqstp, __be32 *p, struct
xdr_init_decode
(
&
xdr
,
&
rqstp
->
rq_rcv_buf
,
p
);
status
=
decode_compound_hdr
(
&
xdr
,
&
hdr
);
if
(
status
)
goto
out
;
status
=
decode_sequence
(
&
xdr
,
&
res
->
seq_res
,
rqstp
);
if
(
status
)
goto
out
;
status
=
decode_putfh
(
&
xdr
);
...
...
@@ -3773,7 +4385,11 @@ static int nfs4_xdr_dec_access(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_ac
int
status
;
xdr_init_decode
(
&
xdr
,
&
rqstp
->
rq_rcv_buf
,
p
);
if
((
status
=
decode_compound_hdr
(
&
xdr
,
&
hdr
))
!=
0
)
status
=
decode_compound_hdr
(
&
xdr
,
&
hdr
);
if
(
status
)
goto
out
;
status
=
decode_sequence
(
&
xdr
,
&
res
->
seq_res
,
rqstp
);
if
(
status
)
goto
out
;
status
=
decode_putfh
(
&
xdr
);
if
(
status
!=
0
)
...
...
@@ -3796,7 +4412,11 @@ static int nfs4_xdr_dec_lookup(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_lo
int
status
;
xdr_init_decode
(
&
xdr
,
&
rqstp
->
rq_rcv_buf
,
p
);
if
((
status
=
decode_compound_hdr
(
&
xdr
,
&
hdr
))
!=
0
)
status
=
decode_compound_hdr
(
&
xdr
,
&
hdr
);
if
(
status
)
goto
out
;
status
=
decode_sequence
(
&
xdr
,
&
res
->
seq_res
,
rqstp
);
if
(
status
)
goto
out
;
if
((
status
=
decode_putfh
(
&
xdr
))
!=
0
)
goto
out
;
...
...
@@ -3819,7 +4439,11 @@ static int nfs4_xdr_dec_lookup_root(struct rpc_rqst *rqstp, __be32 *p, struct nf
int
status
;
xdr_init_decode
(
&
xdr
,
&
rqstp
->
rq_rcv_buf
,
p
);
if
((
status
=
decode_compound_hdr
(
&
xdr
,
&
hdr
))
!=
0
)
status
=
decode_compound_hdr
(
&
xdr
,
&
hdr
);
if
(
status
)
goto
out
;
status
=
decode_sequence
(
&
xdr
,
&
res
->
seq_res
,
rqstp
);
if
(
status
)
goto
out
;
if
((
status
=
decode_putrootfh
(
&
xdr
))
!=
0
)
goto
out
;
...
...
@@ -3839,7 +4463,11 @@ static int nfs4_xdr_dec_remove(struct rpc_rqst *rqstp, __be32 *p, struct nfs_rem
int
status
;
xdr_init_decode
(
&
xdr
,
&
rqstp
->
rq_rcv_buf
,
p
);
if
((
status
=
decode_compound_hdr
(
&
xdr
,
&
hdr
))
!=
0
)
status
=
decode_compound_hdr
(
&
xdr
,
&
hdr
);
if
(
status
)
goto
out
;
status
=
decode_sequence
(
&
xdr
,
&
res
->
seq_res
,
rqstp
);
if
(
status
)
goto
out
;
if
((
status
=
decode_putfh
(
&
xdr
))
!=
0
)
goto
out
;
...
...
@@ -3860,7 +4488,11 @@ static int nfs4_xdr_dec_rename(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_re
int
status
;
xdr_init_decode
(
&
xdr
,
&
rqstp
->
rq_rcv_buf
,
p
);
if
((
status
=
decode_compound_hdr
(
&
xdr
,
&
hdr
))
!=
0
)
status
=
decode_compound_hdr
(
&
xdr
,
&
hdr
);
if
(
status
)
goto
out
;
status
=
decode_sequence
(
&
xdr
,
&
res
->
seq_res
,
rqstp
);
if
(
status
)
goto
out
;
if
((
status
=
decode_putfh
(
&
xdr
))
!=
0
)
goto
out
;
...
...
@@ -3890,7 +4522,11 @@ static int nfs4_xdr_dec_link(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_link
int
status
;
xdr_init_decode
(
&
xdr
,
&
rqstp
->
rq_rcv_buf
,
p
);
if
((
status
=
decode_compound_hdr
(
&
xdr
,
&
hdr
))
!=
0
)
status
=
decode_compound_hdr
(
&
xdr
,
&
hdr
);
if
(
status
)
goto
out
;
status
=
decode_sequence
(
&
xdr
,
&
res
->
seq_res
,
rqstp
);
if
(
status
)
goto
out
;
if
((
status
=
decode_putfh
(
&
xdr
))
!=
0
)
goto
out
;
...
...
@@ -3923,7 +4559,11 @@ static int nfs4_xdr_dec_create(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_cr
int
status
;
xdr_init_decode
(
&
xdr
,
&
rqstp
->
rq_rcv_buf
,
p
);
if
((
status
=
decode_compound_hdr
(
&
xdr
,
&
hdr
))
!=
0
)
status
=
decode_compound_hdr
(
&
xdr
,
&
hdr
);
if
(
status
)
goto
out
;
status
=
decode_sequence
(
&
xdr
,
&
res
->
seq_res
,
rqstp
);
if
(
status
)
goto
out
;
if
((
status
=
decode_putfh
(
&
xdr
))
!=
0
)
goto
out
;
...
...
@@ -3961,6 +4601,9 @@ static int nfs4_xdr_dec_getattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_g
xdr_init_decode
(
&
xdr
,
&
rqstp
->
rq_rcv_buf
,
p
);
status
=
decode_compound_hdr
(
&
xdr
,
&
hdr
);
if
(
status
)
goto
out
;
status
=
decode_sequence
(
&
xdr
,
&
res
->
seq_res
,
rqstp
);
if
(
status
)
goto
out
;
status
=
decode_putfh
(
&
xdr
);
...
...
@@ -3979,12 +4622,13 @@ nfs4_xdr_enc_setacl(struct rpc_rqst *req, __be32 *p, struct nfs_setaclargs *args
{
struct
xdr_stream
xdr
;
struct
compound_hdr
hdr
=
{
.
nops
=
0
,
.
minorversion
=
nfs4_xdr_minorversion
(
&
args
->
seq_args
)
,
};
int
status
;
xdr_init_encode
(
&
xdr
,
&
req
->
rq_snd_buf
,
p
);
encode_compound_hdr
(
&
xdr
,
&
hdr
);
encode_compound_hdr
(
&
xdr
,
req
,
&
hdr
);
encode_sequence
(
&
xdr
,
&
args
->
seq_args
,
&
hdr
);
encode_putfh
(
&
xdr
,
args
->
fh
,
&
hdr
);
status
=
encode_setacl
(
&
xdr
,
args
,
&
hdr
);
encode_nops
(
&
hdr
);
...
...
@@ -3995,7 +4639,8 @@ nfs4_xdr_enc_setacl(struct rpc_rqst *req, __be32 *p, struct nfs_setaclargs *args
* Decode SETACL response
*/
static
int
nfs4_xdr_dec_setacl
(
struct
rpc_rqst
*
rqstp
,
__be32
*
p
,
void
*
res
)
nfs4_xdr_dec_setacl
(
struct
rpc_rqst
*
rqstp
,
__be32
*
p
,
struct
nfs_setaclres
*
res
)
{
struct
xdr_stream
xdr
;
struct
compound_hdr
hdr
;
...
...
@@ -4003,12 +4648,15 @@ nfs4_xdr_dec_setacl(struct rpc_rqst *rqstp, __be32 *p, void *res)
xdr_init_decode
(
&
xdr
,
&
rqstp
->
rq_rcv_buf
,
p
);
status
=
decode_compound_hdr
(
&
xdr
,
&
hdr
);
if
(
status
)
goto
out
;
status
=
decode_sequence
(
&
xdr
,
&
res
->
seq_res
,
rqstp
);
if
(
status
)
goto
out
;
status
=
decode_putfh
(
&
xdr
);
if
(
status
)
goto
out
;
status
=
decode_setattr
(
&
xdr
,
res
);
status
=
decode_setattr
(
&
xdr
);
out:
return
status
;
}
...
...
@@ -4017,7 +4665,8 @@ nfs4_xdr_dec_setacl(struct rpc_rqst *rqstp, __be32 *p, void *res)
* Decode GETACL response
*/
static
int
nfs4_xdr_dec_getacl
(
struct
rpc_rqst
*
rqstp
,
__be32
*
p
,
size_t
*
acl_len
)
nfs4_xdr_dec_getacl
(
struct
rpc_rqst
*
rqstp
,
__be32
*
p
,
struct
nfs_getaclres
*
res
)
{
struct
xdr_stream
xdr
;
struct
compound_hdr
hdr
;
...
...
@@ -4025,12 +4674,15 @@ nfs4_xdr_dec_getacl(struct rpc_rqst *rqstp, __be32 *p, size_t *acl_len)
xdr_init_decode
(
&
xdr
,
&
rqstp
->
rq_rcv_buf
,
p
);
status
=
decode_compound_hdr
(
&
xdr
,
&
hdr
);
if
(
status
)
goto
out
;
status
=
decode_sequence
(
&
xdr
,
&
res
->
seq_res
,
rqstp
);
if
(
status
)
goto
out
;
status
=
decode_putfh
(
&
xdr
);
if
(
status
)
goto
out
;
status
=
decode_getacl
(
&
xdr
,
rqstp
,
acl_len
);
status
=
decode_getacl
(
&
xdr
,
rqstp
,
&
res
->
acl_len
);
out:
return
status
;
...
...
@@ -4047,6 +4699,9 @@ static int nfs4_xdr_dec_close(struct rpc_rqst *rqstp, __be32 *p, struct nfs_clos
xdr_init_decode
(
&
xdr
,
&
rqstp
->
rq_rcv_buf
,
p
);
status
=
decode_compound_hdr
(
&
xdr
,
&
hdr
);
if
(
status
)
goto
out
;
status
=
decode_sequence
(
&
xdr
,
&
res
->
seq_res
,
rqstp
);
if
(
status
)
goto
out
;
status
=
decode_putfh
(
&
xdr
);
...
...
@@ -4077,6 +4732,9 @@ static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, __be32 *p, struct nfs_openr
xdr_init_decode
(
&
xdr
,
&
rqstp
->
rq_rcv_buf
,
p
);
status
=
decode_compound_hdr
(
&
xdr
,
&
hdr
);
if
(
status
)
goto
out
;
status
=
decode_sequence
(
&
xdr
,
&
res
->
seq_res
,
rqstp
);
if
(
status
)
goto
out
;
status
=
decode_putfh
(
&
xdr
);
...
...
@@ -4131,6 +4789,9 @@ static int nfs4_xdr_dec_open_noattr(struct rpc_rqst *rqstp, __be32 *p, struct nf
xdr_init_decode
(
&
xdr
,
&
rqstp
->
rq_rcv_buf
,
p
);
status
=
decode_compound_hdr
(
&
xdr
,
&
hdr
);
if
(
status
)
goto
out
;
status
=
decode_sequence
(
&
xdr
,
&
res
->
seq_res
,
rqstp
);
if
(
status
)
goto
out
;
status
=
decode_putfh
(
&
xdr
);
...
...
@@ -4155,12 +4816,15 @@ static int nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs_se
xdr_init_decode
(
&
xdr
,
&
rqstp
->
rq_rcv_buf
,
p
);
status
=
decode_compound_hdr
(
&
xdr
,
&
hdr
);
if
(
status
)
goto
out
;
status
=
decode_sequence
(
&
xdr
,
&
res
->
seq_res
,
rqstp
);
if
(
status
)
goto
out
;
status
=
decode_putfh
(
&
xdr
);
if
(
status
)
goto
out
;
status
=
decode_setattr
(
&
xdr
,
res
);
status
=
decode_setattr
(
&
xdr
);
if
(
status
)
goto
out
;
decode_getfattr
(
&
xdr
,
res
->
fattr
,
res
->
server
);
...
...
@@ -4179,6 +4843,9 @@ static int nfs4_xdr_dec_lock(struct rpc_rqst *rqstp, __be32 *p, struct nfs_lock_
xdr_init_decode
(
&
xdr
,
&
rqstp
->
rq_rcv_buf
,
p
);
status
=
decode_compound_hdr
(
&
xdr
,
&
hdr
);
if
(
status
)
goto
out
;
status
=
decode_sequence
(
&
xdr
,
&
res
->
seq_res
,
rqstp
);
if
(
status
)
goto
out
;
status
=
decode_putfh
(
&
xdr
);
...
...
@@ -4200,6 +4867,9 @@ static int nfs4_xdr_dec_lockt(struct rpc_rqst *rqstp, __be32 *p, struct nfs_lock
xdr_init_decode
(
&
xdr
,
&
rqstp
->
rq_rcv_buf
,
p
);
status
=
decode_compound_hdr
(
&
xdr
,
&
hdr
);
if
(
status
)
goto
out
;
status
=
decode_sequence
(
&
xdr
,
&
res
->
seq_res
,
rqstp
);
if
(
status
)
goto
out
;
status
=
decode_putfh
(
&
xdr
);
...
...
@@ -4221,6 +4891,9 @@ static int nfs4_xdr_dec_locku(struct rpc_rqst *rqstp, __be32 *p, struct nfs_lock
xdr_init_decode
(
&
xdr
,
&
rqstp
->
rq_rcv_buf
,
p
);
status
=
decode_compound_hdr
(
&
xdr
,
&
hdr
);
if
(
status
)
goto
out
;
status
=
decode_sequence
(
&
xdr
,
&
res
->
seq_res
,
rqstp
);
if
(
status
)
goto
out
;
status
=
decode_putfh
(
&
xdr
);
...
...
@@ -4234,7 +4907,8 @@ static int nfs4_xdr_dec_locku(struct rpc_rqst *rqstp, __be32 *p, struct nfs_lock
/*
* Decode READLINK response
*/
static
int
nfs4_xdr_dec_readlink
(
struct
rpc_rqst
*
rqstp
,
__be32
*
p
,
void
*
res
)
static
int
nfs4_xdr_dec_readlink
(
struct
rpc_rqst
*
rqstp
,
__be32
*
p
,
struct
nfs4_readlink_res
*
res
)
{
struct
xdr_stream
xdr
;
struct
compound_hdr
hdr
;
...
...
@@ -4242,6 +4916,9 @@ static int nfs4_xdr_dec_readlink(struct rpc_rqst *rqstp, __be32 *p, void *res)
xdr_init_decode
(
&
xdr
,
&
rqstp
->
rq_rcv_buf
,
p
);
status
=
decode_compound_hdr
(
&
xdr
,
&
hdr
);
if
(
status
)
goto
out
;
status
=
decode_sequence
(
&
xdr
,
&
res
->
seq_res
,
rqstp
);
if
(
status
)
goto
out
;
status
=
decode_putfh
(
&
xdr
);
...
...
@@ -4263,6 +4940,9 @@ static int nfs4_xdr_dec_readdir(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_r
xdr_init_decode
(
&
xdr
,
&
rqstp
->
rq_rcv_buf
,
p
);
status
=
decode_compound_hdr
(
&
xdr
,
&
hdr
);
if
(
status
)
goto
out
;
status
=
decode_sequence
(
&
xdr
,
&
res
->
seq_res
,
rqstp
);
if
(
status
)
goto
out
;
status
=
decode_putfh
(
&
xdr
);
...
...
@@ -4284,6 +4964,9 @@ static int nfs4_xdr_dec_read(struct rpc_rqst *rqstp, __be32 *p, struct nfs_readr
xdr_init_decode
(
&
xdr
,
&
rqstp
->
rq_rcv_buf
,
p
);
status
=
decode_compound_hdr
(
&
xdr
,
&
hdr
);
if
(
status
)
goto
out
;
status
=
decode_sequence
(
&
xdr
,
&
res
->
seq_res
,
rqstp
);
if
(
status
)
goto
out
;
status
=
decode_putfh
(
&
xdr
);
...
...
@@ -4307,6 +4990,9 @@ static int nfs4_xdr_dec_write(struct rpc_rqst *rqstp, __be32 *p, struct nfs_writ
xdr_init_decode
(
&
xdr
,
&
rqstp
->
rq_rcv_buf
,
p
);
status
=
decode_compound_hdr
(
&
xdr
,
&
hdr
);
if
(
status
)
goto
out
;
status
=
decode_sequence
(
&
xdr
,
&
res
->
seq_res
,
rqstp
);
if
(
status
)
goto
out
;
status
=
decode_putfh
(
&
xdr
);
...
...
@@ -4333,6 +5019,9 @@ static int nfs4_xdr_dec_commit(struct rpc_rqst *rqstp, __be32 *p, struct nfs_wri
xdr_init_decode
(
&
xdr
,
&
rqstp
->
rq_rcv_buf
,
p
);
status
=
decode_compound_hdr
(
&
xdr
,
&
hdr
);
if
(
status
)
goto
out
;
status
=
decode_sequence
(
&
xdr
,
&
res
->
seq_res
,
rqstp
);
if
(
status
)
goto
out
;
status
=
decode_putfh
(
&
xdr
);
...
...
@@ -4349,7 +5038,8 @@ static int nfs4_xdr_dec_commit(struct rpc_rqst *rqstp, __be32 *p, struct nfs_wri
/*
* FSINFO request
*/
static
int
nfs4_xdr_dec_fsinfo
(
struct
rpc_rqst
*
req
,
__be32
*
p
,
struct
nfs_fsinfo
*
fsinfo
)
static
int
nfs4_xdr_dec_fsinfo
(
struct
rpc_rqst
*
req
,
__be32
*
p
,
struct
nfs4_fsinfo_res
*
res
)
{
struct
xdr_stream
xdr
;
struct
compound_hdr
hdr
;
...
...
@@ -4357,17 +5047,20 @@ static int nfs4_xdr_dec_fsinfo(struct rpc_rqst *req, __be32 *p, struct nfs_fsinf
xdr_init_decode
(
&
xdr
,
&
req
->
rq_rcv_buf
,
p
);
status
=
decode_compound_hdr
(
&
xdr
,
&
hdr
);
if
(
!
status
)
status
=
decode_sequence
(
&
xdr
,
&
res
->
seq_res
,
req
);
if
(
!
status
)
status
=
decode_putfh
(
&
xdr
);
if
(
!
status
)
status
=
decode_fsinfo
(
&
xdr
,
fsinfo
);
status
=
decode_fsinfo
(
&
xdr
,
res
->
fsinfo
);
return
status
;
}
/*
* PATHCONF request
*/
static
int
nfs4_xdr_dec_pathconf
(
struct
rpc_rqst
*
req
,
__be32
*
p
,
struct
nfs_pathconf
*
pathconf
)
static
int
nfs4_xdr_dec_pathconf
(
struct
rpc_rqst
*
req
,
__be32
*
p
,
struct
nfs4_pathconf_res
*
res
)
{
struct
xdr_stream
xdr
;
struct
compound_hdr
hdr
;
...
...
@@ -4375,17 +5068,20 @@ static int nfs4_xdr_dec_pathconf(struct rpc_rqst *req, __be32 *p, struct nfs_pat
xdr_init_decode
(
&
xdr
,
&
req
->
rq_rcv_buf
,
p
);
status
=
decode_compound_hdr
(
&
xdr
,
&
hdr
);
if
(
!
status
)
status
=
decode_sequence
(
&
xdr
,
&
res
->
seq_res
,
req
);
if
(
!
status
)
status
=
decode_putfh
(
&
xdr
);
if
(
!
status
)
status
=
decode_pathconf
(
&
xdr
,
pathconf
);
status
=
decode_pathconf
(
&
xdr
,
res
->
pathconf
);
return
status
;
}
/*
* STATFS request
*/
static
int
nfs4_xdr_dec_statfs
(
struct
rpc_rqst
*
req
,
__be32
*
p
,
struct
nfs_fsstat
*
fsstat
)
static
int
nfs4_xdr_dec_statfs
(
struct
rpc_rqst
*
req
,
__be32
*
p
,
struct
nfs4_statfs_res
*
res
)
{
struct
xdr_stream
xdr
;
struct
compound_hdr
hdr
;
...
...
@@ -4393,10 +5089,12 @@ static int nfs4_xdr_dec_statfs(struct rpc_rqst *req, __be32 *p, struct nfs_fssta
xdr_init_decode
(
&
xdr
,
&
req
->
rq_rcv_buf
,
p
);
status
=
decode_compound_hdr
(
&
xdr
,
&
hdr
);
if
(
!
status
)
status
=
decode_sequence
(
&
xdr
,
&
res
->
seq_res
,
req
);
if
(
!
status
)
status
=
decode_putfh
(
&
xdr
);
if
(
!
status
)
status
=
decode_statfs
(
&
xdr
,
fsstat
);
status
=
decode_statfs
(
&
xdr
,
res
->
fsstat
);
return
status
;
}
...
...
@@ -4410,7 +5108,11 @@ static int nfs4_xdr_dec_server_caps(struct rpc_rqst *req, __be32 *p, struct nfs4
int
status
;
xdr_init_decode
(
&
xdr
,
&
req
->
rq_rcv_buf
,
p
);
if
((
status
=
decode_compound_hdr
(
&
xdr
,
&
hdr
))
!=
0
)
status
=
decode_compound_hdr
(
&
xdr
,
&
hdr
);
if
(
status
)
goto
out
;
status
=
decode_sequence
(
&
xdr
,
&
res
->
seq_res
,
req
);
if
(
status
)
goto
out
;
if
((
status
=
decode_putfh
(
&
xdr
))
!=
0
)
goto
out
;
...
...
@@ -4483,7 +5185,10 @@ static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp, __be32 *p, struct nf
xdr_init_decode
(
&
xdr
,
&
rqstp
->
rq_rcv_buf
,
p
);
status
=
decode_compound_hdr
(
&
xdr
,
&
hdr
);
if
(
status
!=
0
)
if
(
status
)
goto
out
;
status
=
decode_sequence
(
&
xdr
,
&
res
->
seq_res
,
rqstp
);
if
(
status
)
goto
out
;
status
=
decode_putfh
(
&
xdr
);
if
(
status
!=
0
)
...
...
@@ -4497,7 +5202,8 @@ static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp, __be32 *p, struct nf
/*
* FS_LOCATIONS request
*/
static
int
nfs4_xdr_dec_fs_locations
(
struct
rpc_rqst
*
req
,
__be32
*
p
,
struct
nfs4_fs_locations
*
res
)
static
int
nfs4_xdr_dec_fs_locations
(
struct
rpc_rqst
*
req
,
__be32
*
p
,
struct
nfs4_fs_locations_res
*
res
)
{
struct
xdr_stream
xdr
;
struct
compound_hdr
hdr
;
...
...
@@ -4505,18 +5211,113 @@ static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req, __be32 *p, struct nfs
xdr_init_decode
(
&
xdr
,
&
req
->
rq_rcv_buf
,
p
);
status
=
decode_compound_hdr
(
&
xdr
,
&
hdr
);
if
(
status
!=
0
)
if
(
status
)
goto
out
;
status
=
decode_sequence
(
&
xdr
,
&
res
->
seq_res
,
req
);
if
(
status
)
goto
out
;
if
((
status
=
decode_putfh
(
&
xdr
))
!=
0
)
goto
out
;
if
((
status
=
decode_lookup
(
&
xdr
))
!=
0
)
goto
out
;
xdr_enter_page
(
&
xdr
,
PAGE_SIZE
);
status
=
decode_getfattr
(
&
xdr
,
&
res
->
fattr
,
res
->
server
);
status
=
decode_getfattr
(
&
xdr
,
&
res
->
fs_locations
->
fattr
,
res
->
fs_locations
->
server
);
out:
return
status
;
}
#if defined(CONFIG_NFS_V4_1)
/*
* EXCHANGE_ID request
*/
static
int
nfs4_xdr_dec_exchange_id
(
struct
rpc_rqst
*
rqstp
,
uint32_t
*
p
,
void
*
res
)
{
struct
xdr_stream
xdr
;
struct
compound_hdr
hdr
;
int
status
;
xdr_init_decode
(
&
xdr
,
&
rqstp
->
rq_rcv_buf
,
p
);
status
=
decode_compound_hdr
(
&
xdr
,
&
hdr
);
if
(
!
status
)
status
=
decode_exchange_id
(
&
xdr
,
res
);
return
status
;
}
/*
* a CREATE_SESSION request
*/
static
int
nfs4_xdr_dec_create_session
(
struct
rpc_rqst
*
rqstp
,
uint32_t
*
p
,
struct
nfs41_create_session_res
*
res
)
{
struct
xdr_stream
xdr
;
struct
compound_hdr
hdr
;
int
status
;
xdr_init_decode
(
&
xdr
,
&
rqstp
->
rq_rcv_buf
,
p
);
status
=
decode_compound_hdr
(
&
xdr
,
&
hdr
);
if
(
!
status
)
status
=
decode_create_session
(
&
xdr
,
res
);
return
status
;
}
/*
* a DESTROY_SESSION request
*/
static
int
nfs4_xdr_dec_destroy_session
(
struct
rpc_rqst
*
rqstp
,
uint32_t
*
p
,
void
*
dummy
)
{
struct
xdr_stream
xdr
;
struct
compound_hdr
hdr
;
int
status
;
xdr_init_decode
(
&
xdr
,
&
rqstp
->
rq_rcv_buf
,
p
);
status
=
decode_compound_hdr
(
&
xdr
,
&
hdr
);
if
(
!
status
)
status
=
decode_destroy_session
(
&
xdr
,
dummy
);
return
status
;
}
/*
* a SEQUENCE request
*/
static
int
nfs4_xdr_dec_sequence
(
struct
rpc_rqst
*
rqstp
,
uint32_t
*
p
,
struct
nfs4_sequence_res
*
res
)
{
struct
xdr_stream
xdr
;
struct
compound_hdr
hdr
;
int
status
;
xdr_init_decode
(
&
xdr
,
&
rqstp
->
rq_rcv_buf
,
p
);
status
=
decode_compound_hdr
(
&
xdr
,
&
hdr
);
if
(
!
status
)
status
=
decode_sequence
(
&
xdr
,
res
,
rqstp
);
return
status
;
}
/*
* a GET_LEASE_TIME request
*/
static
int
nfs4_xdr_dec_get_lease_time
(
struct
rpc_rqst
*
rqstp
,
uint32_t
*
p
,
struct
nfs4_get_lease_time_res
*
res
)
{
struct
xdr_stream
xdr
;
struct
compound_hdr
hdr
;
int
status
;
xdr_init_decode
(
&
xdr
,
&
rqstp
->
rq_rcv_buf
,
p
);
status
=
decode_compound_hdr
(
&
xdr
,
&
hdr
);
if
(
!
status
)
status
=
decode_sequence
(
&
xdr
,
&
res
->
lr_seq_res
,
rqstp
);
if
(
!
status
)
status
=
decode_putrootfh
(
&
xdr
);
if
(
!
status
)
status
=
decode_fsinfo
(
&
xdr
,
res
->
lr_fsinfo
);
return
status
;
}
#endif
/* CONFIG_NFS_V4_1 */
__be32
*
nfs4_decode_dirent
(
__be32
*
p
,
struct
nfs_entry
*
entry
,
int
plus
)
{
uint32_t
bitmap
[
2
]
=
{
0
};
...
...
@@ -4686,6 +5487,13 @@ struct rpc_procinfo nfs4_procedures[] = {
PROC
(
GETACL
,
enc_getacl
,
dec_getacl
),
PROC
(
SETACL
,
enc_setacl
,
dec_setacl
),
PROC
(
FS_LOCATIONS
,
enc_fs_locations
,
dec_fs_locations
),
#if defined(CONFIG_NFS_V4_1)
PROC
(
EXCHANGE_ID
,
enc_exchange_id
,
dec_exchange_id
),
PROC
(
CREATE_SESSION
,
enc_create_session
,
dec_create_session
),
PROC
(
DESTROY_SESSION
,
enc_destroy_session
,
dec_destroy_session
),
PROC
(
SEQUENCE
,
enc_sequence
,
dec_sequence
),
PROC
(
GET_LEASE_TIME
,
enc_get_lease_time
,
dec_get_lease_time
),
#endif
/* CONFIG_NFS_V4_1 */
};
struct
rpc_version
nfs_version4
=
{
...
...
fs/nfs/read.c
View file @
301933a0
...
...
@@ -22,6 +22,7 @@
#include <asm/system.h>
#include "nfs4_fs.h"
#include "internal.h"
#include "iostat.h"
#include "fscache.h"
...
...
@@ -46,6 +47,7 @@ struct nfs_read_data *nfs_readdata_alloc(unsigned int pagecount)
memset
(
p
,
0
,
sizeof
(
*
p
));
INIT_LIST_HEAD
(
&
p
->
pages
);
p
->
npages
=
pagecount
;
p
->
res
.
seq_res
.
sr_slotid
=
NFS4_MAX_SLOT_TABLE
;
if
(
pagecount
<=
ARRAY_SIZE
(
p
->
page_array
))
p
->
pagevec
=
p
->
page_array
;
else
{
...
...
@@ -357,19 +359,25 @@ static void nfs_readpage_retry(struct rpc_task *task, struct nfs_read_data *data
struct
nfs_readres
*
resp
=
&
data
->
res
;
if
(
resp
->
eof
||
resp
->
count
==
argp
->
count
)
return
;
goto
out
;
/* This is a short read! */
nfs_inc_stats
(
data
->
inode
,
NFSIOS_SHORTREAD
);
/* Has the server at least made some progress? */
if
(
resp
->
count
==
0
)
return
;
goto
out
;
/* Yes, so retry the read at the end of the data */
argp
->
offset
+=
resp
->
count
;
argp
->
pgbase
+=
resp
->
count
;
argp
->
count
-=
resp
->
count
;
rpc_restart_call
(
task
);
nfs4_restart_rpc
(
task
,
NFS_SERVER
(
data
->
inode
)
->
nfs_client
);
return
;
out:
nfs4_sequence_free_slot
(
NFS_SERVER
(
data
->
inode
)
->
nfs_client
,
&
data
->
res
.
seq_res
);
return
;
}
/*
...
...
@@ -406,7 +414,23 @@ static void nfs_readpage_release_partial(void *calldata)
nfs_readdata_release
(
calldata
);
}
#if defined(CONFIG_NFS_V4_1)
void
nfs_read_prepare
(
struct
rpc_task
*
task
,
void
*
calldata
)
{
struct
nfs_read_data
*
data
=
calldata
;
if
(
nfs4_setup_sequence
(
NFS_SERVER
(
data
->
inode
)
->
nfs_client
,
&
data
->
args
.
seq_args
,
&
data
->
res
.
seq_res
,
0
,
task
))
return
;
rpc_call_start
(
task
);
}
#endif
/* CONFIG_NFS_V4_1 */
static
const
struct
rpc_call_ops
nfs_read_partial_ops
=
{
#if defined(CONFIG_NFS_V4_1)
.
rpc_call_prepare
=
nfs_read_prepare
,
#endif
/* CONFIG_NFS_V4_1 */
.
rpc_call_done
=
nfs_readpage_result_partial
,
.
rpc_release
=
nfs_readpage_release_partial
,
};
...
...
@@ -470,6 +494,9 @@ static void nfs_readpage_release_full(void *calldata)
}
static
const
struct
rpc_call_ops
nfs_read_full_ops
=
{
#if defined(CONFIG_NFS_V4_1)
.
rpc_call_prepare
=
nfs_read_prepare
,
#endif
/* CONFIG_NFS_V4_1 */
.
rpc_call_done
=
nfs_readpage_result_full
,
.
rpc_release
=
nfs_readpage_release_full
,
};
...
...
fs/nfs/super.c
View file @
301933a0
...
...
@@ -90,6 +90,7 @@ enum {
Opt_mountport
,
Opt_mountvers
,
Opt_nfsvers
,
Opt_minorversion
,
/* Mount options that take string arguments */
Opt_sec
,
Opt_proto
,
Opt_mountproto
,
Opt_mounthost
,
...
...
@@ -155,6 +156,7 @@ static const match_table_t nfs_mount_option_tokens = {
{
Opt_mountvers
,
"mountvers=%u"
},
{
Opt_nfsvers
,
"nfsvers=%u"
},
{
Opt_nfsvers
,
"vers=%u"
},
{
Opt_minorversion
,
"minorversion=%u"
},
{
Opt_sec
,
"sec=%s"
},
{
Opt_proto
,
"proto=%s"
},
...
...
@@ -1211,6 +1213,13 @@ static int nfs_parse_mount_options(char *raw,
nfs_parse_invalid_value
(
"nfsvers"
);
}
break
;
case
Opt_minorversion
:
if
(
match_int
(
args
,
&
option
))
return
0
;
if
(
option
<
0
||
option
>
NFS4_MAX_MINOR_VERSION
)
return
0
;
mnt
->
minorversion
=
option
;
break
;
/*
* options that take text values
...
...
@@ -2263,6 +2272,7 @@ static int nfs4_validate_mount_data(void *options,
args
->
nfs_server
.
port
=
NFS_PORT
;
/* 2049 unless user set port= */
args
->
auth_flavors
[
0
]
=
RPC_AUTH_UNIX
;
args
->
auth_flavor_len
=
0
;
args
->
minorversion
=
0
;
switch
(
data
->
version
)
{
case
1
:
...
...
@@ -2477,12 +2487,13 @@ static void nfs4_kill_super(struct super_block *sb)
{
struct
nfs_server
*
server
=
NFS_SB
(
sb
);
dprintk
(
"--> %s
\n
"
,
__func__
);
nfs_super_return_all_delegations
(
sb
);
kill_anon_super
(
sb
);
nfs4_renewd_prepare_shutdown
(
server
);
nfs_fscache_release_super_cookie
(
sb
);
nfs_free_server
(
server
);
dprintk
(
"<-- %s
\n
"
,
__func__
);
}
/*
...
...
fs/nfs/unlink.c
View file @
301933a0
...
...
@@ -15,6 +15,7 @@
#include <linux/wait.h>
#include "internal.h"
#include "nfs4_fs.h"
struct
nfs_unlinkdata
{
struct
hlist_node
list
;
...
...
@@ -82,7 +83,7 @@ static void nfs_async_unlink_done(struct rpc_task *task, void *calldata)
struct
inode
*
dir
=
data
->
dir
;
if
(
!
NFS_PROTO
(
dir
)
->
unlink_done
(
task
,
dir
))
rpc_restart_call
(
task
);
nfs4_restart_rpc
(
task
,
NFS_SERVER
(
dir
)
->
nfs_client
);
}
/**
...
...
@@ -102,9 +103,25 @@ static void nfs_async_unlink_release(void *calldata)
nfs_sb_deactive
(
sb
);
}
#if defined(CONFIG_NFS_V4_1)
void
nfs_unlink_prepare
(
struct
rpc_task
*
task
,
void
*
calldata
)
{
struct
nfs_unlinkdata
*
data
=
calldata
;
struct
nfs_server
*
server
=
NFS_SERVER
(
data
->
dir
);
if
(
nfs4_setup_sequence
(
server
->
nfs_client
,
&
data
->
args
.
seq_args
,
&
data
->
res
.
seq_res
,
1
,
task
))
return
;
rpc_call_start
(
task
);
}
#endif
/* CONFIG_NFS_V4_1 */
static
const
struct
rpc_call_ops
nfs_unlink_ops
=
{
.
rpc_call_done
=
nfs_async_unlink_done
,
.
rpc_release
=
nfs_async_unlink_release
,
#if defined(CONFIG_NFS_V4_1)
.
rpc_call_prepare
=
nfs_unlink_prepare
,
#endif
/* CONFIG_NFS_V4_1 */
};
static
int
nfs_do_call_unlink
(
struct
dentry
*
parent
,
struct
inode
*
dir
,
struct
nfs_unlinkdata
*
data
)
...
...
@@ -241,6 +258,7 @@ nfs_async_unlink(struct inode *dir, struct dentry *dentry)
status
=
PTR_ERR
(
data
->
cred
);
goto
out_free
;
}
data
->
res
.
seq_res
.
sr_slotid
=
NFS4_MAX_SLOT_TABLE
;
status
=
-
EBUSY
;
spin_lock
(
&
dentry
->
d_lock
);
...
...
fs/nfs/write.c
View file @
301933a0
...
...
@@ -25,6 +25,7 @@
#include "delegation.h"
#include "internal.h"
#include "iostat.h"
#include "nfs4_fs.h"
#define NFSDBG_FACILITY NFSDBG_PAGECACHE
...
...
@@ -52,6 +53,7 @@ struct nfs_write_data *nfs_commitdata_alloc(void)
if
(
p
)
{
memset
(
p
,
0
,
sizeof
(
*
p
));
INIT_LIST_HEAD
(
&
p
->
pages
);
p
->
res
.
seq_res
.
sr_slotid
=
NFS4_MAX_SLOT_TABLE
;
}
return
p
;
}
...
...
@@ -71,6 +73,7 @@ struct nfs_write_data *nfs_writedata_alloc(unsigned int pagecount)
memset
(
p
,
0
,
sizeof
(
*
p
));
INIT_LIST_HEAD
(
&
p
->
pages
);
p
->
npages
=
pagecount
;
p
->
res
.
seq_res
.
sr_slotid
=
NFS4_MAX_SLOT_TABLE
;
if
(
pagecount
<=
ARRAY_SIZE
(
p
->
page_array
))
p
->
pagevec
=
p
->
page_array
;
else
{
...
...
@@ -1048,7 +1051,23 @@ static void nfs_writeback_release_partial(void *calldata)
nfs_writedata_release
(
calldata
);
}
#if defined(CONFIG_NFS_V4_1)
void
nfs_write_prepare
(
struct
rpc_task
*
task
,
void
*
calldata
)
{
struct
nfs_write_data
*
data
=
calldata
;
struct
nfs_client
*
clp
=
(
NFS_SERVER
(
data
->
inode
))
->
nfs_client
;
if
(
nfs4_setup_sequence
(
clp
,
&
data
->
args
.
seq_args
,
&
data
->
res
.
seq_res
,
1
,
task
))
return
;
rpc_call_start
(
task
);
}
#endif
/* CONFIG_NFS_V4_1 */
static
const
struct
rpc_call_ops
nfs_write_partial_ops
=
{
#if defined(CONFIG_NFS_V4_1)
.
rpc_call_prepare
=
nfs_write_prepare
,
#endif
/* CONFIG_NFS_V4_1 */
.
rpc_call_done
=
nfs_writeback_done_partial
,
.
rpc_release
=
nfs_writeback_release_partial
,
};
...
...
@@ -1111,6 +1130,9 @@ static void nfs_writeback_release_full(void *calldata)
}
static
const
struct
rpc_call_ops
nfs_write_full_ops
=
{
#if defined(CONFIG_NFS_V4_1)
.
rpc_call_prepare
=
nfs_write_prepare
,
#endif
/* CONFIG_NFS_V4_1 */
.
rpc_call_done
=
nfs_writeback_done_full
,
.
rpc_release
=
nfs_writeback_release_full
,
};
...
...
@@ -1123,6 +1145,7 @@ int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data)
{
struct
nfs_writeargs
*
argp
=
&
data
->
args
;
struct
nfs_writeres
*
resp
=
&
data
->
res
;
struct
nfs_server
*
server
=
NFS_SERVER
(
data
->
inode
);
int
status
;
dprintk
(
"NFS: %5u nfs_writeback_done (status %d)
\n
"
,
...
...
@@ -1155,7 +1178,7 @@ int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data)
if
(
time_before
(
complain
,
jiffies
))
{
dprintk
(
"NFS: faulty NFS server %s:"
" (committed = %d) != (stable = %d)
\n
"
,
NFS_SERVER
(
data
->
inode
)
->
nfs_client
->
cl_hostname
,
server
->
nfs_client
->
cl_hostname
,
resp
->
verf
->
committed
,
argp
->
stable
);
complain
=
jiffies
+
300
*
HZ
;
}
...
...
@@ -1181,7 +1204,7 @@ int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data)
*/
argp
->
stable
=
NFS_FILE_SYNC
;
}
rpc_restart_call
(
task
);
nfs4_restart_rpc
(
task
,
server
->
nfs_client
);
return
-
EAGAIN
;
}
if
(
time_before
(
complain
,
jiffies
))
{
...
...
@@ -1193,6 +1216,7 @@ int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data)
/* Can't do anything about it except throw an error. */
task
->
tk_status
=
-
EIO
;
}
nfs4_sequence_free_slot
(
server
->
nfs_client
,
&
data
->
res
.
seq_res
);
return
0
;
}
...
...
@@ -1349,6 +1373,9 @@ static void nfs_commit_release(void *calldata)
}
static
const
struct
rpc_call_ops
nfs_commit_ops
=
{
#if defined(CONFIG_NFS_V4_1)
.
rpc_call_prepare
=
nfs_write_prepare
,
#endif
/* CONFIG_NFS_V4_1 */
.
rpc_call_done
=
nfs_commit_done
,
.
rpc_release
=
nfs_commit_release
,
};
...
...
include/linux/nfs4.h
View file @
301933a0
...
...
@@ -21,6 +21,7 @@
#define NFS4_FHSIZE 128
#define NFS4_MAXPATHLEN PATH_MAX
#define NFS4_MAXNAMLEN NAME_MAX
#define NFS4_OPAQUE_LIMIT 1024
#define NFS4_MAX_SESSIONID_LEN 16
#define NFS4_ACCESS_READ 0x0001
...
...
@@ -130,6 +131,16 @@
#define NFS4_MAX_UINT64 (~(u64)0)
/* An NFS4 sessions server must support at least NFS4_MAX_OPS operations.
* If a compound requires more operations, adjust NFS4_MAX_OPS accordingly.
*/
#define NFS4_MAX_OPS 8
/* Our NFS4 client back channel server only wants the cb_sequene and the
* actual operation per compound
*/
#define NFS4_MAX_BACK_CHANNEL_OPS 2
enum
nfs4_acl_whotype
{
NFS4_ACL_WHO_NAMED
=
0
,
NFS4_ACL_WHO_OWNER
,
...
...
@@ -462,6 +473,13 @@ enum lock_type4 {
#define NFSPROC4_NULL 0
#define NFSPROC4_COMPOUND 1
#define NFS4_MINOR_VERSION 0
#if defined(CONFIG_NFS_V4_1)
#define NFS4_MAX_MINOR_VERSION 1
#else
#define NFS4_MAX_MINOR_VERSION 0
#endif
/* CONFIG_NFS_V4_1 */
#define NFS4_DEBUG 1
/* Index of predefined Linux client operations */
...
...
include/linux/nfs_fs_sb.h
View file @
301933a0
...
...
@@ -4,11 +4,17 @@
#include <linux/list.h>
#include <linux/backing-dev.h>
#include <linux/wait.h>
#include <linux/nfs_xdr.h>
#include <linux/sunrpc/xprt.h>
#include <asm/atomic.h>
struct
nfs4_session
;
struct
nfs_iostats
;
struct
nlm_host
;
struct
nfs4_sequence_args
;
struct
nfs4_sequence_res
;
struct
nfs_server
;
/*
* The nfs_client identifies our client state to the server.
...
...
@@ -18,6 +24,7 @@ struct nfs_client {
int
cl_cons_state
;
/* current construction state (-ve: init error) */
#define NFS_CS_READY 0
/* ready to be used */
#define NFS_CS_INITING 1
/* busy initialising */
#define NFS_CS_SESSION_INITING 2
/* busy initialising session */
unsigned
long
cl_res_state
;
/* NFS resources state */
#define NFS_CS_CALLBACK 1
/* - callback started */
#define NFS_CS_IDMAP 2
/* - idmap started */
...
...
@@ -32,6 +39,7 @@ struct nfs_client {
const
struct
nfs_rpc_ops
*
rpc_ops
;
/* NFS protocol vector */
int
cl_proto
;
/* Network transport protocol */
u32
cl_minorversion
;
/* NFSv4 minorversion */
struct
rpc_cred
*
cl_machine_cred
;
#ifdef CONFIG_NFS_V4
...
...
@@ -63,7 +71,22 @@ struct nfs_client {
*/
char
cl_ipaddr
[
48
];
unsigned
char
cl_id_uniquifier
;
#endif
int
(
*
cl_call_sync
)(
struct
nfs_server
*
server
,
struct
rpc_message
*
msg
,
struct
nfs4_sequence_args
*
args
,
struct
nfs4_sequence_res
*
res
,
int
cache_reply
);
#endif
/* CONFIG_NFS_V4 */
#ifdef CONFIG_NFS_V4_1
/* clientid returned from EXCHANGE_ID, used by session operations */
u64
cl_ex_clid
;
/* The sequence id to use for the next CREATE_SESSION */
u32
cl_seqid
;
/* The flags used for obtaining the clientid during EXCHANGE_ID */
u32
cl_exchange_flags
;
struct
nfs4_session
*
cl_session
;
/* sharred session */
#endif
/* CONFIG_NFS_V4_1 */
#ifdef CONFIG_NFS_FSCACHE
struct
fscache_cookie
*
fscache
;
/* client index cache cookie */
...
...
@@ -145,4 +168,46 @@ struct nfs_server {
#define NFS_CAP_ACLS (1U << 3)
#define NFS_CAP_ATOMIC_OPEN (1U << 4)
/* maximum number of slots to use */
#define NFS4_MAX_SLOT_TABLE RPC_MAX_SLOT_TABLE
#if defined(CONFIG_NFS_V4_1)
/* Sessions */
#define SLOT_TABLE_SZ (NFS4_MAX_SLOT_TABLE/(8*sizeof(long)))
struct
nfs4_slot_table
{
struct
nfs4_slot
*
slots
;
/* seqid per slot */
unsigned
long
used_slots
[
SLOT_TABLE_SZ
];
/* used/unused bitmap */
spinlock_t
slot_tbl_lock
;
struct
rpc_wait_queue
slot_tbl_waitq
;
/* allocators may wait here */
int
max_slots
;
/* # slots in table */
int
highest_used_slotid
;
/* sent to server on each SEQ.
* op for dynamic resizing */
};
static
inline
int
slot_idx
(
struct
nfs4_slot_table
*
tbl
,
struct
nfs4_slot
*
sp
)
{
return
sp
-
tbl
->
slots
;
}
/*
* Session related parameters
*/
struct
nfs4_session
{
struct
nfs4_sessionid
sess_id
;
u32
flags
;
unsigned
long
session_state
;
u32
hash_alg
;
u32
ssv_len
;
/* The fore and back channel */
struct
nfs4_channel_attrs
fc_attrs
;
struct
nfs4_slot_table
fc_slot_table
;
struct
nfs4_channel_attrs
bc_attrs
;
struct
nfs4_slot_table
bc_slot_table
;
struct
nfs_client
*
clp
;
};
#endif
/* CONFIG_NFS_V4_1 */
#endif
include/linux/nfs_xdr.h
View file @
301933a0
...
...
@@ -145,6 +145,44 @@ struct nfs4_change_info {
};
struct
nfs_seqid
;
/* nfs41 sessions channel attributes */
struct
nfs4_channel_attrs
{
u32
headerpadsz
;
u32
max_rqst_sz
;
u32
max_resp_sz
;
u32
max_resp_sz_cached
;
u32
max_ops
;
u32
max_reqs
;
};
/* nfs41 sessions slot seqid */
struct
nfs4_slot
{
u32
seq_nr
;
};
struct
nfs4_sequence_args
{
struct
nfs4_session
*
sa_session
;
u8
sa_slotid
;
u8
sa_cache_this
;
};
struct
nfs4_sequence_res
{
struct
nfs4_session
*
sr_session
;
u8
sr_slotid
;
/* slot used to send request */
unsigned
long
sr_renewal_time
;
int
sr_status
;
/* sequence operation status */
};
struct
nfs4_get_lease_time_args
{
struct
nfs4_sequence_args
la_seq_args
;
};
struct
nfs4_get_lease_time_res
{
struct
nfs_fsinfo
*
lr_fsinfo
;
struct
nfs4_sequence_res
lr_seq_res
;
};
/*
* Arguments to the open call.
*/
...
...
@@ -165,6 +203,7 @@ struct nfs_openargs {
const
struct
nfs_server
*
server
;
/* Needed for ID mapping */
const
u32
*
bitmask
;
__u32
claim
;
struct
nfs4_sequence_args
seq_args
;
};
struct
nfs_openres
{
...
...
@@ -181,6 +220,7 @@ struct nfs_openres {
__u32
do_recall
;
__u64
maxsize
;
__u32
attrset
[
NFS4_BITMAP_SIZE
];
struct
nfs4_sequence_res
seq_res
;
};
/*
...
...
@@ -206,6 +246,7 @@ struct nfs_closeargs {
struct
nfs_seqid
*
seqid
;
fmode_t
fmode
;
const
u32
*
bitmask
;
struct
nfs4_sequence_args
seq_args
;
};
struct
nfs_closeres
{
...
...
@@ -213,6 +254,7 @@ struct nfs_closeres {
struct
nfs_fattr
*
fattr
;
struct
nfs_seqid
*
seqid
;
const
struct
nfs_server
*
server
;
struct
nfs4_sequence_res
seq_res
;
};
/*
* * Arguments to the lock,lockt, and locku call.
...
...
@@ -233,12 +275,14 @@ struct nfs_lock_args {
unsigned
char
block
:
1
;
unsigned
char
reclaim
:
1
;
unsigned
char
new_lock_owner
:
1
;
struct
nfs4_sequence_args
seq_args
;
};
struct
nfs_lock_res
{
nfs4_stateid
stateid
;
struct
nfs_seqid
*
lock_seqid
;
struct
nfs_seqid
*
open_seqid
;
struct
nfs4_sequence_res
seq_res
;
};
struct
nfs_locku_args
{
...
...
@@ -246,32 +290,38 @@ struct nfs_locku_args {
struct
file_lock
*
fl
;
struct
nfs_seqid
*
seqid
;
nfs4_stateid
*
stateid
;
struct
nfs4_sequence_args
seq_args
;
};
struct
nfs_locku_res
{
nfs4_stateid
stateid
;
struct
nfs_seqid
*
seqid
;
struct
nfs4_sequence_res
seq_res
;
};
struct
nfs_lockt_args
{
struct
nfs_fh
*
fh
;
struct
file_lock
*
fl
;
struct
nfs_lowner
lock_owner
;
struct
nfs4_sequence_args
seq_args
;
};
struct
nfs_lockt_res
{
struct
file_lock
*
denied
;
/* LOCK, LOCKT failed */
struct
nfs4_sequence_res
seq_res
;
};
struct
nfs4_delegreturnargs
{
const
struct
nfs_fh
*
fhandle
;
const
nfs4_stateid
*
stateid
;
const
u32
*
bitmask
;
struct
nfs4_sequence_args
seq_args
;
};
struct
nfs4_delegreturnres
{
struct
nfs_fattr
*
fattr
;
const
struct
nfs_server
*
server
;
struct
nfs4_sequence_res
seq_res
;
};
/*
...
...
@@ -284,12 +334,14 @@ struct nfs_readargs {
__u32
count
;
unsigned
int
pgbase
;
struct
page
**
pages
;
struct
nfs4_sequence_args
seq_args
;
};
struct
nfs_readres
{
struct
nfs_fattr
*
fattr
;
__u32
count
;
int
eof
;
struct
nfs4_sequence_res
seq_res
;
};
/*
...
...
@@ -304,6 +356,7 @@ struct nfs_writeargs {
unsigned
int
pgbase
;
struct
page
**
pages
;
const
u32
*
bitmask
;
struct
nfs4_sequence_args
seq_args
;
};
struct
nfs_writeverf
{
...
...
@@ -316,6 +369,7 @@ struct nfs_writeres {
struct
nfs_writeverf
*
verf
;
__u32
count
;
const
struct
nfs_server
*
server
;
struct
nfs4_sequence_res
seq_res
;
};
/*
...
...
@@ -325,12 +379,14 @@ struct nfs_removeargs {
const
struct
nfs_fh
*
fh
;
struct
qstr
name
;
const
u32
*
bitmask
;
struct
nfs4_sequence_args
seq_args
;
};
struct
nfs_removeres
{
const
struct
nfs_server
*
server
;
struct
nfs4_change_info
cinfo
;
struct
nfs_fattr
dir_attr
;
struct
nfs4_sequence_res
seq_res
;
};
/*
...
...
@@ -383,6 +439,7 @@ struct nfs_setattrargs {
struct
iattr
*
iap
;
const
struct
nfs_server
*
server
;
/* Needed for name mapping */
const
u32
*
bitmask
;
struct
nfs4_sequence_args
seq_args
;
};
struct
nfs_setaclargs
{
...
...
@@ -390,6 +447,11 @@ struct nfs_setaclargs {
size_t
acl_len
;
unsigned
int
acl_pgbase
;
struct
page
**
acl_pages
;
struct
nfs4_sequence_args
seq_args
;
};
struct
nfs_setaclres
{
struct
nfs4_sequence_res
seq_res
;
};
struct
nfs_getaclargs
{
...
...
@@ -397,11 +459,18 @@ struct nfs_getaclargs {
size_t
acl_len
;
unsigned
int
acl_pgbase
;
struct
page
**
acl_pages
;
struct
nfs4_sequence_args
seq_args
;
};
struct
nfs_getaclres
{
size_t
acl_len
;
struct
nfs4_sequence_res
seq_res
;
};
struct
nfs_setattrres
{
struct
nfs_fattr
*
fattr
;
const
struct
nfs_server
*
server
;
struct
nfs4_sequence_res
seq_res
;
};
struct
nfs_linkargs
{
...
...
@@ -583,6 +652,7 @@ struct nfs4_accessargs {
const
struct
nfs_fh
*
fh
;
const
u32
*
bitmask
;
u32
access
;
struct
nfs4_sequence_args
seq_args
;
};
struct
nfs4_accessres
{
...
...
@@ -590,6 +660,7 @@ struct nfs4_accessres {
struct
nfs_fattr
*
fattr
;
u32
supported
;
u32
access
;
struct
nfs4_sequence_res
seq_res
;
};
struct
nfs4_create_arg
{
...
...
@@ -609,6 +680,7 @@ struct nfs4_create_arg {
const
struct
iattr
*
attrs
;
const
struct
nfs_fh
*
dir_fh
;
const
u32
*
bitmask
;
struct
nfs4_sequence_args
seq_args
;
};
struct
nfs4_create_res
{
...
...
@@ -617,21 +689,30 @@ struct nfs4_create_res {
struct
nfs_fattr
*
fattr
;
struct
nfs4_change_info
dir_cinfo
;
struct
nfs_fattr
*
dir_fattr
;
struct
nfs4_sequence_res
seq_res
;
};
struct
nfs4_fsinfo_arg
{
const
struct
nfs_fh
*
fh
;
const
u32
*
bitmask
;
struct
nfs4_sequence_args
seq_args
;
};
struct
nfs4_fsinfo_res
{
struct
nfs_fsinfo
*
fsinfo
;
struct
nfs4_sequence_res
seq_res
;
};
struct
nfs4_getattr_arg
{
const
struct
nfs_fh
*
fh
;
const
u32
*
bitmask
;
struct
nfs4_sequence_args
seq_args
;
};
struct
nfs4_getattr_res
{
const
struct
nfs_server
*
server
;
struct
nfs_fattr
*
fattr
;
struct
nfs4_sequence_res
seq_res
;
};
struct
nfs4_link_arg
{
...
...
@@ -639,6 +720,7 @@ struct nfs4_link_arg {
const
struct
nfs_fh
*
dir_fh
;
const
struct
qstr
*
name
;
const
u32
*
bitmask
;
struct
nfs4_sequence_args
seq_args
;
};
struct
nfs4_link_res
{
...
...
@@ -646,6 +728,7 @@ struct nfs4_link_res {
struct
nfs_fattr
*
fattr
;
struct
nfs4_change_info
cinfo
;
struct
nfs_fattr
*
dir_attr
;
struct
nfs4_sequence_res
seq_res
;
};
...
...
@@ -653,21 +736,30 @@ struct nfs4_lookup_arg {
const
struct
nfs_fh
*
dir_fh
;
const
struct
qstr
*
name
;
const
u32
*
bitmask
;
struct
nfs4_sequence_args
seq_args
;
};
struct
nfs4_lookup_res
{
const
struct
nfs_server
*
server
;
struct
nfs_fattr
*
fattr
;
struct
nfs_fh
*
fh
;
struct
nfs4_sequence_res
seq_res
;
};
struct
nfs4_lookup_root_arg
{
const
u32
*
bitmask
;
struct
nfs4_sequence_args
seq_args
;
};
struct
nfs4_pathconf_arg
{
const
struct
nfs_fh
*
fh
;
const
u32
*
bitmask
;
struct
nfs4_sequence_args
seq_args
;
};
struct
nfs4_pathconf_res
{
struct
nfs_pathconf
*
pathconf
;
struct
nfs4_sequence_res
seq_res
;
};
struct
nfs4_readdir_arg
{
...
...
@@ -678,11 +770,13 @@ struct nfs4_readdir_arg {
struct
page
**
pages
;
/* zero-copy data */
unsigned
int
pgbase
;
/* zero-copy data */
const
u32
*
bitmask
;
struct
nfs4_sequence_args
seq_args
;
};
struct
nfs4_readdir_res
{
nfs4_verifier
verifier
;
unsigned
int
pgbase
;
struct
nfs4_sequence_res
seq_res
;
};
struct
nfs4_readlink
{
...
...
@@ -690,6 +784,11 @@ struct nfs4_readlink {
unsigned
int
pgbase
;
unsigned
int
pglen
;
/* zero-copy data */
struct
page
**
pages
;
/* zero-copy data */
struct
nfs4_sequence_args
seq_args
;
};
struct
nfs4_readlink_res
{
struct
nfs4_sequence_res
seq_res
;
};
struct
nfs4_rename_arg
{
...
...
@@ -698,6 +797,7 @@ struct nfs4_rename_arg {
const
struct
qstr
*
old_name
;
const
struct
qstr
*
new_name
;
const
u32
*
bitmask
;
struct
nfs4_sequence_args
seq_args
;
};
struct
nfs4_rename_res
{
...
...
@@ -706,6 +806,7 @@ struct nfs4_rename_res {
struct
nfs_fattr
*
old_fattr
;
struct
nfs4_change_info
new_cinfo
;
struct
nfs_fattr
*
new_fattr
;
struct
nfs4_sequence_res
seq_res
;
};
#define NFS4_SETCLIENTID_NAMELEN (127)
...
...
@@ -724,6 +825,17 @@ struct nfs4_setclientid {
struct
nfs4_statfs_arg
{
const
struct
nfs_fh
*
fh
;
const
u32
*
bitmask
;
struct
nfs4_sequence_args
seq_args
;
};
struct
nfs4_statfs_res
{
struct
nfs_fsstat
*
fsstat
;
struct
nfs4_sequence_res
seq_res
;
};
struct
nfs4_server_caps_arg
{
struct
nfs_fh
*
fhandle
;
struct
nfs4_sequence_args
seq_args
;
};
struct
nfs4_server_caps_res
{
...
...
@@ -731,6 +843,7 @@ struct nfs4_server_caps_res {
u32
acl_bitmask
;
u32
has_links
;
u32
has_symlinks
;
struct
nfs4_sequence_res
seq_res
;
};
struct
nfs4_string
{
...
...
@@ -765,10 +878,68 @@ struct nfs4_fs_locations_arg {
const
struct
qstr
*
name
;
struct
page
*
page
;
const
u32
*
bitmask
;
struct
nfs4_sequence_args
seq_args
;
};
struct
nfs4_fs_locations_res
{
struct
nfs4_fs_locations
*
fs_locations
;
struct
nfs4_sequence_res
seq_res
;
};
#endif
/* CONFIG_NFS_V4 */
struct
nfstime4
{
u64
seconds
;
u32
nseconds
;
};
#ifdef CONFIG_NFS_V4_1
struct
nfs_impl_id4
{
u32
domain_len
;
char
*
domain
;
u32
name_len
;
char
*
name
;
struct
nfstime4
date
;
};
#define NFS4_EXCHANGE_ID_LEN (48)
struct
nfs41_exchange_id_args
{
struct
nfs_client
*
client
;
nfs4_verifier
*
verifier
;
unsigned
int
id_len
;
char
id
[
NFS4_EXCHANGE_ID_LEN
];
u32
flags
;
};
struct
server_owner
{
uint64_t
minor_id
;
uint32_t
major_id_sz
;
char
major_id
[
NFS4_OPAQUE_LIMIT
];
};
struct
server_scope
{
uint32_t
server_scope_sz
;
char
server_scope
[
NFS4_OPAQUE_LIMIT
];
};
struct
nfs41_exchange_id_res
{
struct
nfs_client
*
client
;
u32
flags
;
};
struct
nfs41_create_session_args
{
struct
nfs_client
*
client
;
uint32_t
flags
;
uint32_t
cb_program
;
struct
nfs4_channel_attrs
fc_attrs
;
/* Fore Channel */
struct
nfs4_channel_attrs
bc_attrs
;
/* Back Channel */
};
struct
nfs41_create_session_res
{
struct
nfs_client
*
client
;
};
#endif
/* CONFIG_NFS_V4_1 */
struct
nfs_page
;
#define NFS_PAGEVEC_SIZE (8U)
...
...
include/linux/nfsd/state.h
View file @
301933a0
...
...
@@ -41,7 +41,6 @@
#include <linux/kref.h>
#include <linux/sunrpc/clnt.h>
#define NFS4_OPAQUE_LIMIT 1024
typedef
struct
{
u32
cl_boot
;
u32
cl_id
;
...
...
include/linux/sunrpc/bc_xprt.h
0 → 100644
View file @
301933a0
/******************************************************************************
(c) 2008 NetApp. All Rights Reserved.
NetApp provides this source code under the GPL v2 License.
The GPL v2 license is available at
http://opensource.org/licenses/gpl-license.php.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/
/*
* Functions to create and manage the backchannel
*/
#ifndef _LINUX_SUNRPC_BC_XPRT_H
#define _LINUX_SUNRPC_BC_XPRT_H
#include <linux/sunrpc/svcsock.h>
#include <linux/sunrpc/xprt.h>
#include <linux/sunrpc/sched.h>
#ifdef CONFIG_NFS_V4_1
struct
rpc_rqst
*
xprt_alloc_bc_request
(
struct
rpc_xprt
*
xprt
);
void
xprt_free_bc_request
(
struct
rpc_rqst
*
req
);
int
xprt_setup_backchannel
(
struct
rpc_xprt
*
,
unsigned
int
min_reqs
);
void
xprt_destroy_backchannel
(
struct
rpc_xprt
*
,
int
max_reqs
);
void
bc_release_request
(
struct
rpc_task
*
);
int
bc_send
(
struct
rpc_rqst
*
req
);
#else
/* CONFIG_NFS_V4_1 */
static
inline
int
xprt_setup_backchannel
(
struct
rpc_xprt
*
xprt
,
unsigned
int
min_reqs
)
{
return
0
;
}
#endif
/* CONFIG_NFS_V4_1 */
#endif
/* _LINUX_SUNRPC_BC_XPRT_H */
include/linux/sunrpc/clnt.h
View file @
301933a0
...
...
@@ -143,6 +143,7 @@ int rpc_call_sync(struct rpc_clnt *clnt,
const
struct
rpc_message
*
msg
,
int
flags
);
struct
rpc_task
*
rpc_call_null
(
struct
rpc_clnt
*
clnt
,
struct
rpc_cred
*
cred
,
int
flags
);
void
rpc_restart_call_prepare
(
struct
rpc_task
*
);
void
rpc_restart_call
(
struct
rpc_task
*
);
void
rpc_setbufsize
(
struct
rpc_clnt
*
,
unsigned
int
,
unsigned
int
);
size_t
rpc_max_payload
(
struct
rpc_clnt
*
);
...
...
include/linux/sunrpc/sched.h
View file @
301933a0
...
...
@@ -210,6 +210,8 @@ struct rpc_wait_queue {
*/
struct
rpc_task
*
rpc_new_task
(
const
struct
rpc_task_setup
*
);
struct
rpc_task
*
rpc_run_task
(
const
struct
rpc_task_setup
*
);
struct
rpc_task
*
rpc_run_bc_task
(
struct
rpc_rqst
*
req
,
const
struct
rpc_call_ops
*
ops
);
void
rpc_put_task
(
struct
rpc_task
*
);
void
rpc_exit_task
(
struct
rpc_task
*
);
void
rpc_release_calldata
(
const
struct
rpc_call_ops
*
,
void
*
);
...
...
@@ -237,6 +239,7 @@ void rpc_show_tasks(void);
int
rpc_init_mempool
(
void
);
void
rpc_destroy_mempool
(
void
);
extern
struct
workqueue_struct
*
rpciod_workqueue
;
void
rpc_prepare_task
(
struct
rpc_task
*
task
);
static
inline
void
rpc_exit
(
struct
rpc_task
*
task
,
int
status
)
{
...
...
include/linux/sunrpc/svc.h
View file @
301933a0
...
...
@@ -96,6 +96,15 @@ struct svc_serv {
svc_thread_fn
sv_function
;
/* main function for threads */
unsigned
int
sv_drc_max_pages
;
/* Total pages for DRC */
unsigned
int
sv_drc_pages_used
;
/* DRC pages used */
#if defined(CONFIG_NFS_V4_1)
struct
list_head
sv_cb_list
;
/* queue for callback requests
* that arrive over the same
* connection */
spinlock_t
sv_cb_lock
;
/* protects the svc_cb_list */
wait_queue_head_t
sv_cb_waitq
;
/* sleep here if there are no
* entries in the svc_cb_list */
struct
svc_xprt
*
bc_xprt
;
#endif
/* CONFIG_NFS_V4_1 */
};
/*
...
...
@@ -411,6 +420,8 @@ int svc_set_num_threads(struct svc_serv *, struct svc_pool *, int);
int
svc_pool_stats_open
(
struct
svc_serv
*
serv
,
struct
file
*
file
);
void
svc_destroy
(
struct
svc_serv
*
);
int
svc_process
(
struct
svc_rqst
*
);
int
bc_svc_process
(
struct
svc_serv
*
,
struct
rpc_rqst
*
,
struct
svc_rqst
*
);
int
svc_register
(
const
struct
svc_serv
*
,
const
int
,
const
unsigned
short
,
const
unsigned
short
);
...
...
include/linux/sunrpc/svcsock.h
View file @
301933a0
...
...
@@ -42,6 +42,8 @@ int svc_sock_names(char *buf, struct svc_serv *serv, char *toclose);
int
svc_addsock
(
struct
svc_serv
*
serv
,
int
fd
,
char
*
name_return
);
void
svc_init_xprt_sock
(
void
);
void
svc_cleanup_xprt_sock
(
void
);
struct
svc_xprt
*
svc_sock_create
(
struct
svc_serv
*
serv
,
int
prot
);
void
svc_sock_destroy
(
struct
svc_xprt
*
);
/*
* svc_makesock socket characteristics
...
...
include/linux/sunrpc/xprt.h
View file @
301933a0
...
...
@@ -67,7 +67,8 @@ struct rpc_rqst {
struct
rpc_task
*
rq_task
;
/* RPC task data */
__be32
rq_xid
;
/* request XID */
int
rq_cong
;
/* has incremented xprt->cong */
int
rq_received
;
/* receive completed */
int
rq_reply_bytes_recvd
;
/* number of reply */
/* bytes received */
u32
rq_seqno
;
/* gss seq no. used on req. */
int
rq_enc_pages_num
;
struct
page
**
rq_enc_pages
;
/* scratch pages for use by
...
...
@@ -97,6 +98,12 @@ struct rpc_rqst {
unsigned
long
rq_xtime
;
/* when transmitted */
int
rq_ntrans
;
#if defined(CONFIG_NFS_V4_1)
struct
list_head
rq_bc_list
;
/* Callback service list */
unsigned
long
rq_bc_pa_state
;
/* Backchannel prealloc state */
struct
list_head
rq_bc_pa_list
;
/* Backchannel prealloc list */
#endif
/* CONFIG_NFS_V4_1 */
};
#define rq_svec rq_snd_buf.head
#define rq_slen rq_snd_buf.len
...
...
@@ -174,6 +181,15 @@ struct rpc_xprt {
spinlock_t
reserve_lock
;
/* lock slot table */
u32
xid
;
/* Next XID value to use */
struct
rpc_task
*
snd_task
;
/* Task blocked in send */
#if defined(CONFIG_NFS_V4_1)
struct
svc_serv
*
bc_serv
;
/* The RPC service which will */
/* process the callback */
unsigned
int
bc_alloc_count
;
/* Total number of preallocs */
spinlock_t
bc_pa_lock
;
/* Protects the preallocated
* items */
struct
list_head
bc_pa_list
;
/* List of preallocated
* backchannel rpc_rqst's */
#endif
/* CONFIG_NFS_V4_1 */
struct
list_head
recv
;
struct
{
...
...
@@ -192,6 +208,26 @@ struct rpc_xprt {
const
char
*
address_strings
[
RPC_DISPLAY_MAX
];
};
#if defined(CONFIG_NFS_V4_1)
/*
* Backchannel flags
*/
#define RPC_BC_PA_IN_USE 0x0001
/* Preallocated backchannel */
/* buffer in use */
#endif
/* CONFIG_NFS_V4_1 */
#if defined(CONFIG_NFS_V4_1)
static
inline
int
bc_prealloc
(
struct
rpc_rqst
*
req
)
{
return
test_bit
(
RPC_BC_PA_IN_USE
,
&
req
->
rq_bc_pa_state
);
}
#else
static
inline
int
bc_prealloc
(
struct
rpc_rqst
*
req
)
{
return
0
;
}
#endif
/* CONFIG_NFS_V4_1 */
struct
xprt_create
{
int
ident
;
/* XPRT_TRANSPORT identifier */
struct
sockaddr
*
srcaddr
;
/* optional local address */
...
...
net/sunrpc/Makefile
View file @
301933a0
...
...
@@ -13,5 +13,6 @@ sunrpc-y := clnt.o xprt.o socklib.o xprtsock.o sched.o \
rpcb_clnt.o timer.o xdr.o
\
sunrpc_syms.o cache.o rpc_pipe.o
\
svc_xprt.o
sunrpc-$(CONFIG_NFS_V4_1)
+=
backchannel_rqst.o bc_svc.o
sunrpc-$(CONFIG_PROC_FS)
+=
stats.o
sunrpc-$(CONFIG_SYSCTL)
+=
sysctl.o
net/sunrpc/backchannel_rqst.c
0 → 100644
View file @
301933a0
/******************************************************************************
(c) 2007 Network Appliance, Inc. All Rights Reserved.
(c) 2009 NetApp. All Rights Reserved.
NetApp provides this source code under the GPL v2 License.
The GPL v2 license is available at
http://opensource.org/licenses/gpl-license.php.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/
#include <linux/tcp.h>
#include <linux/sunrpc/xprt.h>
#ifdef RPC_DEBUG
#define RPCDBG_FACILITY RPCDBG_TRANS
#endif
#if defined(CONFIG_NFS_V4_1)
/*
* Helper routines that track the number of preallocation elements
* on the transport.
*/
static
inline
int
xprt_need_to_requeue
(
struct
rpc_xprt
*
xprt
)
{
return
xprt
->
bc_alloc_count
>
0
;
}
static
inline
void
xprt_inc_alloc_count
(
struct
rpc_xprt
*
xprt
,
unsigned
int
n
)
{
xprt
->
bc_alloc_count
+=
n
;
}
static
inline
int
xprt_dec_alloc_count
(
struct
rpc_xprt
*
xprt
,
unsigned
int
n
)
{
return
xprt
->
bc_alloc_count
-=
n
;
}
/*
* Free the preallocated rpc_rqst structure and the memory
* buffers hanging off of it.
*/
static
void
xprt_free_allocation
(
struct
rpc_rqst
*
req
)
{
struct
xdr_buf
*
xbufp
;
dprintk
(
"RPC: free allocations for req= %p
\n
"
,
req
);
BUG_ON
(
test_bit
(
RPC_BC_PA_IN_USE
,
&
req
->
rq_bc_pa_state
));
xbufp
=
&
req
->
rq_private_buf
;
free_page
((
unsigned
long
)
xbufp
->
head
[
0
].
iov_base
);
xbufp
=
&
req
->
rq_snd_buf
;
free_page
((
unsigned
long
)
xbufp
->
head
[
0
].
iov_base
);
list_del
(
&
req
->
rq_bc_pa_list
);
kfree
(
req
);
}
/*
* Preallocate up to min_reqs structures and related buffers for use
* by the backchannel. This function can be called multiple times
* when creating new sessions that use the same rpc_xprt. The
* preallocated buffers are added to the pool of resources used by
* the rpc_xprt. Anyone of these resources may be used used by an
* incoming callback request. It's up to the higher levels in the
* stack to enforce that the maximum number of session slots is not
* being exceeded.
*
* Some callback arguments can be large. For example, a pNFS server
* using multiple deviceids. The list can be unbound, but the client
* has the ability to tell the server the maximum size of the callback
* requests. Each deviceID is 16 bytes, so allocate one page
* for the arguments to have enough room to receive a number of these
* deviceIDs. The NFS client indicates to the pNFS server that its
* callback requests can be up to 4096 bytes in size.
*/
int
xprt_setup_backchannel
(
struct
rpc_xprt
*
xprt
,
unsigned
int
min_reqs
)
{
struct
page
*
page_rcv
=
NULL
,
*
page_snd
=
NULL
;
struct
xdr_buf
*
xbufp
=
NULL
;
struct
rpc_rqst
*
req
,
*
tmp
;
struct
list_head
tmp_list
;
int
i
;
dprintk
(
"RPC: setup backchannel transport
\n
"
);
/*
* We use a temporary list to keep track of the preallocated
* buffers. Once we're done building the list we splice it
* into the backchannel preallocation list off of the rpc_xprt
* struct. This helps minimize the amount of time the list
* lock is held on the rpc_xprt struct. It also makes cleanup
* easier in case of memory allocation errors.
*/
INIT_LIST_HEAD
(
&
tmp_list
);
for
(
i
=
0
;
i
<
min_reqs
;
i
++
)
{
/* Pre-allocate one backchannel rpc_rqst */
req
=
kzalloc
(
sizeof
(
struct
rpc_rqst
),
GFP_KERNEL
);
if
(
req
==
NULL
)
{
printk
(
KERN_ERR
"Failed to create bc rpc_rqst
\n
"
);
goto
out_free
;
}
/* Add the allocated buffer to the tmp list */
dprintk
(
"RPC: adding req= %p
\n
"
,
req
);
list_add
(
&
req
->
rq_bc_pa_list
,
&
tmp_list
);
req
->
rq_xprt
=
xprt
;
INIT_LIST_HEAD
(
&
req
->
rq_list
);
INIT_LIST_HEAD
(
&
req
->
rq_bc_list
);
/* Preallocate one XDR receive buffer */
page_rcv
=
alloc_page
(
GFP_KERNEL
);
if
(
page_rcv
==
NULL
)
{
printk
(
KERN_ERR
"Failed to create bc receive xbuf
\n
"
);
goto
out_free
;
}
xbufp
=
&
req
->
rq_rcv_buf
;
xbufp
->
head
[
0
].
iov_base
=
page_address
(
page_rcv
);
xbufp
->
head
[
0
].
iov_len
=
PAGE_SIZE
;
xbufp
->
tail
[
0
].
iov_base
=
NULL
;
xbufp
->
tail
[
0
].
iov_len
=
0
;
xbufp
->
page_len
=
0
;
xbufp
->
len
=
PAGE_SIZE
;
xbufp
->
buflen
=
PAGE_SIZE
;
/* Preallocate one XDR send buffer */
page_snd
=
alloc_page
(
GFP_KERNEL
);
if
(
page_snd
==
NULL
)
{
printk
(
KERN_ERR
"Failed to create bc snd xbuf
\n
"
);
goto
out_free
;
}
xbufp
=
&
req
->
rq_snd_buf
;
xbufp
->
head
[
0
].
iov_base
=
page_address
(
page_snd
);
xbufp
->
head
[
0
].
iov_len
=
0
;
xbufp
->
tail
[
0
].
iov_base
=
NULL
;
xbufp
->
tail
[
0
].
iov_len
=
0
;
xbufp
->
page_len
=
0
;
xbufp
->
len
=
0
;
xbufp
->
buflen
=
PAGE_SIZE
;
}
/*
* Add the temporary list to the backchannel preallocation list
*/
spin_lock_bh
(
&
xprt
->
bc_pa_lock
);
list_splice
(
&
tmp_list
,
&
xprt
->
bc_pa_list
);
xprt_inc_alloc_count
(
xprt
,
min_reqs
);
spin_unlock_bh
(
&
xprt
->
bc_pa_lock
);
dprintk
(
"RPC: setup backchannel transport done
\n
"
);
return
0
;
out_free:
/*
* Memory allocation failed, free the temporary list
*/
list_for_each_entry_safe
(
req
,
tmp
,
&
tmp_list
,
rq_bc_pa_list
)
xprt_free_allocation
(
req
);
dprintk
(
"RPC: setup backchannel transport failed
\n
"
);
return
-
1
;
}
EXPORT_SYMBOL
(
xprt_setup_backchannel
);
/*
* Destroys the backchannel preallocated structures.
* Since these structures may have been allocated by multiple calls
* to xprt_setup_backchannel, we only destroy up to the maximum number
* of reqs specified by the caller.
* @xprt: the transport holding the preallocated strucures
* @max_reqs the maximum number of preallocated structures to destroy
*/
void
xprt_destroy_backchannel
(
struct
rpc_xprt
*
xprt
,
unsigned
int
max_reqs
)
{
struct
rpc_rqst
*
req
=
NULL
,
*
tmp
=
NULL
;
dprintk
(
"RPC: destroy backchannel transport
\n
"
);
BUG_ON
(
max_reqs
==
0
);
spin_lock_bh
(
&
xprt
->
bc_pa_lock
);
xprt_dec_alloc_count
(
xprt
,
max_reqs
);
list_for_each_entry_safe
(
req
,
tmp
,
&
xprt
->
bc_pa_list
,
rq_bc_pa_list
)
{
dprintk
(
"RPC: req=%p
\n
"
,
req
);
xprt_free_allocation
(
req
);
if
(
--
max_reqs
==
0
)
break
;
}
spin_unlock_bh
(
&
xprt
->
bc_pa_lock
);
dprintk
(
"RPC: backchannel list empty= %s
\n
"
,
list_empty
(
&
xprt
->
bc_pa_list
)
?
"true"
:
"false"
);
}
EXPORT_SYMBOL
(
xprt_destroy_backchannel
);
/*
* One or more rpc_rqst structure have been preallocated during the
* backchannel setup. Buffer space for the send and private XDR buffers
* has been preallocated as well. Use xprt_alloc_bc_request to allocate
* to this request. Use xprt_free_bc_request to return it.
*
* Return an available rpc_rqst, otherwise NULL if non are available.
*/
struct
rpc_rqst
*
xprt_alloc_bc_request
(
struct
rpc_xprt
*
xprt
)
{
struct
rpc_rqst
*
req
;
dprintk
(
"RPC: allocate a backchannel request
\n
"
);
spin_lock_bh
(
&
xprt
->
bc_pa_lock
);
if
(
!
list_empty
(
&
xprt
->
bc_pa_list
))
{
req
=
list_first_entry
(
&
xprt
->
bc_pa_list
,
struct
rpc_rqst
,
rq_bc_pa_list
);
list_del
(
&
req
->
rq_bc_pa_list
);
}
else
{
req
=
NULL
;
}
spin_unlock_bh
(
&
xprt
->
bc_pa_lock
);
if
(
req
!=
NULL
)
{
set_bit
(
RPC_BC_PA_IN_USE
,
&
req
->
rq_bc_pa_state
);
req
->
rq_reply_bytes_recvd
=
0
;
req
->
rq_bytes_sent
=
0
;
memcpy
(
&
req
->
rq_private_buf
,
&
req
->
rq_rcv_buf
,
sizeof
(
req
->
rq_private_buf
));
}
dprintk
(
"RPC: backchannel req=%p
\n
"
,
req
);
return
req
;
}
/*
* Return the preallocated rpc_rqst structure and XDR buffers
* associated with this rpc_task.
*/
void
xprt_free_bc_request
(
struct
rpc_rqst
*
req
)
{
struct
rpc_xprt
*
xprt
=
req
->
rq_xprt
;
dprintk
(
"RPC: free backchannel req=%p
\n
"
,
req
);
smp_mb__before_clear_bit
();
BUG_ON
(
!
test_bit
(
RPC_BC_PA_IN_USE
,
&
req
->
rq_bc_pa_state
));
clear_bit
(
RPC_BC_PA_IN_USE
,
&
req
->
rq_bc_pa_state
);
smp_mb__after_clear_bit
();
if
(
!
xprt_need_to_requeue
(
xprt
))
{
/*
* The last remaining session was destroyed while this
* entry was in use. Free the entry and don't attempt
* to add back to the list because there is no need to
* have anymore preallocated entries.
*/
dprintk
(
"RPC: Last session removed req=%p
\n
"
,
req
);
xprt_free_allocation
(
req
);
return
;
}
/*
* Return it to the list of preallocations so that it
* may be reused by a new callback request.
*/
spin_lock_bh
(
&
xprt
->
bc_pa_lock
);
list_add
(
&
req
->
rq_bc_pa_list
,
&
xprt
->
bc_pa_list
);
spin_unlock_bh
(
&
xprt
->
bc_pa_lock
);
}
#endif
/* CONFIG_NFS_V4_1 */
net/sunrpc/bc_svc.c
0 → 100644
View file @
301933a0
/******************************************************************************
(c) 2007 Network Appliance, Inc. All Rights Reserved.
(c) 2009 NetApp. All Rights Reserved.
NetApp provides this source code under the GPL v2 License.
The GPL v2 license is available at
http://opensource.org/licenses/gpl-license.php.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/
/*
* The NFSv4.1 callback service helper routines.
* They implement the transport level processing required to send the
* reply over an existing open connection previously established by the client.
*/
#if defined(CONFIG_NFS_V4_1)
#include <linux/module.h>
#include <linux/sunrpc/xprt.h>
#include <linux/sunrpc/sched.h>
#include <linux/sunrpc/bc_xprt.h>
#define RPCDBG_FACILITY RPCDBG_SVCDSP
void
bc_release_request
(
struct
rpc_task
*
task
)
{
struct
rpc_rqst
*
req
=
task
->
tk_rqstp
;
dprintk
(
"RPC: bc_release_request: task= %p
\n
"
,
task
);
/*
* Release this request only if it's a backchannel
* preallocated request
*/
if
(
!
bc_prealloc
(
req
))
return
;
xprt_free_bc_request
(
req
);
}
/* Empty callback ops */
static
const
struct
rpc_call_ops
nfs41_callback_ops
=
{
};
/*
* Send the callback reply
*/
int
bc_send
(
struct
rpc_rqst
*
req
)
{
struct
rpc_task
*
task
;
int
ret
;
dprintk
(
"RPC: bc_send req= %p
\n
"
,
req
);
task
=
rpc_run_bc_task
(
req
,
&
nfs41_callback_ops
);
if
(
IS_ERR
(
task
))
ret
=
PTR_ERR
(
task
);
else
{
BUG_ON
(
atomic_read
(
&
task
->
tk_count
)
!=
1
);
ret
=
task
->
tk_status
;
rpc_put_task
(
task
);
}
return
ret
;
dprintk
(
"RPC: bc_send ret= %d
\n
"
,
ret
);
}
#endif
/* CONFIG_NFS_V4_1 */
net/sunrpc/clnt.c
View file @
301933a0
...
...
@@ -36,7 +36,9 @@
#include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/rpc_pipe_fs.h>
#include <linux/sunrpc/metrics.h>
#include <linux/sunrpc/bc_xprt.h>
#include "sunrpc.h"
#ifdef RPC_DEBUG
# define RPCDBG_FACILITY RPCDBG_CALL
...
...
@@ -63,6 +65,9 @@ static void call_decode(struct rpc_task *task);
static
void
call_bind
(
struct
rpc_task
*
task
);
static
void
call_bind_status
(
struct
rpc_task
*
task
);
static
void
call_transmit
(
struct
rpc_task
*
task
);
#if defined(CONFIG_NFS_V4_1)
static
void
call_bc_transmit
(
struct
rpc_task
*
task
);
#endif
/* CONFIG_NFS_V4_1 */
static
void
call_status
(
struct
rpc_task
*
task
);
static
void
call_transmit_status
(
struct
rpc_task
*
task
);
static
void
call_refresh
(
struct
rpc_task
*
task
);
...
...
@@ -613,6 +618,50 @@ rpc_call_async(struct rpc_clnt *clnt, const struct rpc_message *msg, int flags,
}
EXPORT_SYMBOL_GPL
(
rpc_call_async
);
#if defined(CONFIG_NFS_V4_1)
/**
* rpc_run_bc_task - Allocate a new RPC task for backchannel use, then run
* rpc_execute against it
* @ops: RPC call ops
*/
struct
rpc_task
*
rpc_run_bc_task
(
struct
rpc_rqst
*
req
,
const
struct
rpc_call_ops
*
tk_ops
)
{
struct
rpc_task
*
task
;
struct
xdr_buf
*
xbufp
=
&
req
->
rq_snd_buf
;
struct
rpc_task_setup
task_setup_data
=
{
.
callback_ops
=
tk_ops
,
};
dprintk
(
"RPC: rpc_run_bc_task req= %p
\n
"
,
req
);
/*
* Create an rpc_task to send the data
*/
task
=
rpc_new_task
(
&
task_setup_data
);
if
(
!
task
)
{
xprt_free_bc_request
(
req
);
goto
out
;
}
task
->
tk_rqstp
=
req
;
/*
* Set up the xdr_buf length.
* This also indicates that the buffer is XDR encoded already.
*/
xbufp
->
len
=
xbufp
->
head
[
0
].
iov_len
+
xbufp
->
page_len
+
xbufp
->
tail
[
0
].
iov_len
;
task
->
tk_action
=
call_bc_transmit
;
atomic_inc
(
&
task
->
tk_count
);
BUG_ON
(
atomic_read
(
&
task
->
tk_count
)
!=
2
);
rpc_execute
(
task
);
out:
dprintk
(
"RPC: rpc_run_bc_task: task= %p
\n
"
,
task
);
return
task
;
}
#endif
/* CONFIG_NFS_V4_1 */
void
rpc_call_start
(
struct
rpc_task
*
task
)
{
...
...
@@ -694,6 +743,19 @@ void rpc_force_rebind(struct rpc_clnt *clnt)
}
EXPORT_SYMBOL_GPL
(
rpc_force_rebind
);
/*
* Restart an (async) RPC call from the call_prepare state.
* Usually called from within the exit handler.
*/
void
rpc_restart_call_prepare
(
struct
rpc_task
*
task
)
{
if
(
RPC_ASSASSINATED
(
task
))
return
;
task
->
tk_action
=
rpc_prepare_task
;
}
EXPORT_SYMBOL_GPL
(
rpc_restart_call_prepare
);
/*
* Restart an (async) RPC call. Usually called from within the
* exit handler.
...
...
@@ -1085,7 +1147,7 @@ call_transmit(struct rpc_task *task)
* in order to allow access to the socket to other RPC requests.
*/
call_transmit_status
(
task
);
if
(
task
->
tk_msg
.
rpc_proc
->
p_decode
!=
NULL
)
if
(
rpc_reply_expected
(
task
)
)
return
;
task
->
tk_action
=
rpc_exit_task
;
rpc_wake_up_queued_task
(
&
task
->
tk_xprt
->
pending
,
task
);
...
...
@@ -1120,6 +1182,72 @@ call_transmit_status(struct rpc_task *task)
}
}
#if defined(CONFIG_NFS_V4_1)
/*
* 5b. Send the backchannel RPC reply. On error, drop the reply. In
* addition, disconnect on connectivity errors.
*/
static
void
call_bc_transmit
(
struct
rpc_task
*
task
)
{
struct
rpc_rqst
*
req
=
task
->
tk_rqstp
;
BUG_ON
(
task
->
tk_status
!=
0
);
task
->
tk_status
=
xprt_prepare_transmit
(
task
);
if
(
task
->
tk_status
==
-
EAGAIN
)
{
/*
* Could not reserve the transport. Try again after the
* transport is released.
*/
task
->
tk_status
=
0
;
task
->
tk_action
=
call_bc_transmit
;
return
;
}
task
->
tk_action
=
rpc_exit_task
;
if
(
task
->
tk_status
<
0
)
{
printk
(
KERN_NOTICE
"RPC: Could not send backchannel reply "
"error: %d
\n
"
,
task
->
tk_status
);
return
;
}
xprt_transmit
(
task
);
xprt_end_transmit
(
task
);
dprint_status
(
task
);
switch
(
task
->
tk_status
)
{
case
0
:
/* Success */
break
;
case
-
EHOSTDOWN
:
case
-
EHOSTUNREACH
:
case
-
ENETUNREACH
:
case
-
ETIMEDOUT
:
/*
* Problem reaching the server. Disconnect and let the
* forechannel reestablish the connection. The server will
* have to retransmit the backchannel request and we'll
* reprocess it. Since these ops are idempotent, there's no
* need to cache our reply at this time.
*/
printk
(
KERN_NOTICE
"RPC: Could not send backchannel reply "
"error: %d
\n
"
,
task
->
tk_status
);
xprt_conditional_disconnect
(
task
->
tk_xprt
,
req
->
rq_connect_cookie
);
break
;
default:
/*
* We were unable to reply and will have to drop the
* request. The server should reconnect and retransmit.
*/
BUG_ON
(
task
->
tk_status
==
-
EAGAIN
);
printk
(
KERN_NOTICE
"RPC: Could not send backchannel reply "
"error: %d
\n
"
,
task
->
tk_status
);
break
;
}
rpc_wake_up_queued_task
(
&
req
->
rq_xprt
->
pending
,
task
);
}
#endif
/* CONFIG_NFS_V4_1 */
/*
* 6. Sort out the RPC call status
*/
...
...
@@ -1130,8 +1258,8 @@ call_status(struct rpc_task *task)
struct
rpc_rqst
*
req
=
task
->
tk_rqstp
;
int
status
;
if
(
req
->
rq_re
ceive
d
>
0
&&
!
req
->
rq_bytes_sent
)
task
->
tk_status
=
req
->
rq_re
ceive
d
;
if
(
req
->
rq_re
ply_bytes_recv
d
>
0
&&
!
req
->
rq_bytes_sent
)
task
->
tk_status
=
req
->
rq_re
ply_bytes_recv
d
;
dprint_status
(
task
);
...
...
@@ -1248,7 +1376,7 @@ call_decode(struct rpc_task *task)
/*
* Ensure that we see all writes made by xprt_complete_rqst()
* before it changed req->rq_re
ceive
d.
* before it changed req->rq_re
ply_bytes_recv
d.
*/
smp_rmb
();
req
->
rq_rcv_buf
.
len
=
req
->
rq_private_buf
.
len
;
...
...
@@ -1289,7 +1417,7 @@ call_decode(struct rpc_task *task)
task
->
tk_status
=
0
;
/* Note: rpc_verify_header() may have freed the RPC slot */
if
(
task
->
tk_rqstp
==
req
)
{
req
->
rq_re
ceive
d
=
req
->
rq_rcv_buf
.
len
=
0
;
req
->
rq_re
ply_bytes_recv
d
=
req
->
rq_rcv_buf
.
len
=
0
;
if
(
task
->
tk_client
->
cl_discrtry
)
xprt_conditional_disconnect
(
task
->
tk_xprt
,
req
->
rq_connect_cookie
);
...
...
@@ -1377,13 +1505,14 @@ rpc_verify_header(struct rpc_task *task)
}
if
((
len
-=
3
)
<
0
)
goto
out_overflow
;
p
+=
1
;
/* skip XID */
p
+=
1
;
/* skip XID */
if
((
n
=
ntohl
(
*
p
++
))
!=
RPC_REPLY
)
{
dprintk
(
"RPC: %5u %s: not an RPC reply: %x
\n
"
,
task
->
tk_pid
,
__func__
,
n
);
goto
out_garbage
;
}
if
((
n
=
ntohl
(
*
p
++
))
!=
RPC_MSG_ACCEPTED
)
{
if
(
--
len
<
0
)
goto
out_overflow
;
...
...
net/sunrpc/sched.c
View file @
301933a0
...
...
@@ -569,7 +569,7 @@ EXPORT_SYMBOL_GPL(rpc_delay);
/*
* Helper to call task->tk_ops->rpc_call_prepare
*/
static
void
rpc_prepare_task
(
struct
rpc_task
*
task
)
void
rpc_prepare_task
(
struct
rpc_task
*
task
)
{
task
->
tk_ops
->
rpc_call_prepare
(
task
,
task
->
tk_calldata
);
}
...
...
net/sunrpc/stats.c
View file @
301933a0
...
...
@@ -141,12 +141,14 @@ EXPORT_SYMBOL_GPL(rpc_free_iostats);
void
rpc_count_iostats
(
struct
rpc_task
*
task
)
{
struct
rpc_rqst
*
req
=
task
->
tk_rqstp
;
struct
rpc_iostats
*
stats
=
task
->
tk_client
->
cl_metrics
;
struct
rpc_iostats
*
stats
;
struct
rpc_iostats
*
op_metrics
;
long
rtt
,
execute
,
queue
;
if
(
!
stat
s
||
!
req
)
if
(
!
task
->
tk_client
||
!
task
->
tk_client
->
cl_metric
s
||
!
req
)
return
;
stats
=
task
->
tk_client
->
cl_metrics
;
op_metrics
=
&
stats
[
task
->
tk_msg
.
rpc_proc
->
p_statidx
];
op_metrics
->
om_ops
++
;
...
...
@@ -154,7 +156,7 @@ void rpc_count_iostats(struct rpc_task *task)
op_metrics
->
om_timeouts
+=
task
->
tk_timeouts
;
op_metrics
->
om_bytes_sent
+=
task
->
tk_bytes_sent
;
op_metrics
->
om_bytes_recv
+=
req
->
rq_re
ceive
d
;
op_metrics
->
om_bytes_recv
+=
req
->
rq_re
ply_bytes_recv
d
;
queue
=
(
long
)
req
->
rq_xtime
-
task
->
tk_start
;
if
(
queue
<
0
)
...
...
net/sunrpc/sunrpc.h
0 → 100644
View file @
301933a0
/******************************************************************************
(c) 2008 NetApp. All Rights Reserved.
NetApp provides this source code under the GPL v2 License.
The GPL v2 license is available at
http://opensource.org/licenses/gpl-license.php.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/
/*
* Functions and macros used internally by RPC
*/
#ifndef _NET_SUNRPC_SUNRPC_H
#define _NET_SUNRPC_SUNRPC_H
static
inline
int
rpc_reply_expected
(
struct
rpc_task
*
task
)
{
return
(
task
->
tk_msg
.
rpc_proc
!=
NULL
)
&&
(
task
->
tk_msg
.
rpc_proc
->
p_decode
!=
NULL
);
}
#endif
/* _NET_SUNRPC_SUNRPC_H */
net/sunrpc/svc.c
View file @
301933a0
...
...
@@ -25,6 +25,7 @@
#include <linux/sunrpc/stats.h>
#include <linux/sunrpc/svcsock.h>
#include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/bc_xprt.h>
#define RPCDBG_FACILITY RPCDBG_SVCDSP
...
...
@@ -486,6 +487,10 @@ svc_destroy(struct svc_serv *serv)
if
(
svc_serv_is_pooled
(
serv
))
svc_pool_map_put
();
#if defined(CONFIG_NFS_V4_1)
svc_sock_destroy
(
serv
->
bc_xprt
);
#endif
/* CONFIG_NFS_V4_1 */
svc_unregister
(
serv
);
kfree
(
serv
->
sv_pools
);
kfree
(
serv
);
...
...
@@ -970,20 +975,18 @@ svc_printk(struct svc_rqst *rqstp, const char *fmt, ...)
}
/*
*
Process
the RPC request.
*
Common routine for processing
the RPC request.
*/
int
svc_process
(
struct
svc_rqst
*
rqstp
)
static
int
svc_process
_common
(
struct
svc_rqst
*
rqstp
,
struct
kvec
*
argv
,
struct
kvec
*
resv
)
{
struct
svc_program
*
progp
;
struct
svc_version
*
versp
=
NULL
;
/* compiler food */
struct
svc_procedure
*
procp
=
NULL
;
struct
kvec
*
argv
=
&
rqstp
->
rq_arg
.
head
[
0
];
struct
kvec
*
resv
=
&
rqstp
->
rq_res
.
head
[
0
];
struct
svc_serv
*
serv
=
rqstp
->
rq_server
;
kxdrproc_t
xdr
;
__be32
*
statp
;
u32
dir
,
prog
,
vers
,
proc
;
u32
prog
,
vers
,
proc
;
__be32
auth_stat
,
rpc_stat
;
int
auth_res
;
__be32
*
reply_statp
;
...
...
@@ -993,19 +996,6 @@ svc_process(struct svc_rqst *rqstp)
if
(
argv
->
iov_len
<
6
*
4
)
goto
err_short_len
;
/* setup response xdr_buf.
* Initially it has just one page
*/
rqstp
->
rq_resused
=
1
;
resv
->
iov_base
=
page_address
(
rqstp
->
rq_respages
[
0
]);
resv
->
iov_len
=
0
;
rqstp
->
rq_res
.
pages
=
rqstp
->
rq_respages
+
1
;
rqstp
->
rq_res
.
len
=
0
;
rqstp
->
rq_res
.
page_base
=
0
;
rqstp
->
rq_res
.
page_len
=
0
;
rqstp
->
rq_res
.
buflen
=
PAGE_SIZE
;
rqstp
->
rq_res
.
tail
[
0
].
iov_base
=
NULL
;
rqstp
->
rq_res
.
tail
[
0
].
iov_len
=
0
;
/* Will be turned off only in gss privacy case: */
rqstp
->
rq_splice_ok
=
1
;
/* Will be turned off only when NFSv4 Sessions are used */
...
...
@@ -1014,17 +1004,13 @@ svc_process(struct svc_rqst *rqstp)
/* Setup reply header */
rqstp
->
rq_xprt
->
xpt_ops
->
xpo_prep_reply_hdr
(
rqstp
);
rqstp
->
rq_xid
=
svc_getu32
(
argv
);
svc_putu32
(
resv
,
rqstp
->
rq_xid
);
dir
=
svc_getnl
(
argv
);
vers
=
svc_getnl
(
argv
);
/* First words of reply: */
svc_putnl
(
resv
,
1
);
/* REPLY */
if
(
dir
!=
0
)
/* direction != CALL */
goto
err_bad_dir
;
if
(
vers
!=
2
)
/* RPC version number */
goto
err_bad_rpc
;
...
...
@@ -1147,7 +1133,7 @@ svc_process(struct svc_rqst *rqstp)
sendit:
if
(
svc_authorise
(
rqstp
))
goto
dropit
;
return
svc_send
(
rqstp
);
return
1
;
/* Caller can now send it */
dropit:
svc_authorise
(
rqstp
);
/* doesn't hurt to call this twice */
...
...
@@ -1161,12 +1147,6 @@ svc_process(struct svc_rqst *rqstp)
goto
dropit
;
/* drop request */
err_bad_dir:
svc_printk
(
rqstp
,
"bad direction %d, dropping request
\n
"
,
dir
);
serv
->
sv_stats
->
rpcbadfmt
++
;
goto
dropit
;
/* drop request */
err_bad_rpc:
serv
->
sv_stats
->
rpcbadfmt
++
;
svc_putnl
(
resv
,
1
);
/* REJECT */
...
...
@@ -1219,6 +1199,100 @@ svc_process(struct svc_rqst *rqstp)
}
EXPORT_SYMBOL_GPL
(
svc_process
);
/*
* Process the RPC request.
*/
int
svc_process
(
struct
svc_rqst
*
rqstp
)
{
struct
kvec
*
argv
=
&
rqstp
->
rq_arg
.
head
[
0
];
struct
kvec
*
resv
=
&
rqstp
->
rq_res
.
head
[
0
];
struct
svc_serv
*
serv
=
rqstp
->
rq_server
;
u32
dir
;
int
error
;
/*
* Setup response xdr_buf.
* Initially it has just one page
*/
rqstp
->
rq_resused
=
1
;
resv
->
iov_base
=
page_address
(
rqstp
->
rq_respages
[
0
]);
resv
->
iov_len
=
0
;
rqstp
->
rq_res
.
pages
=
rqstp
->
rq_respages
+
1
;
rqstp
->
rq_res
.
len
=
0
;
rqstp
->
rq_res
.
page_base
=
0
;
rqstp
->
rq_res
.
page_len
=
0
;
rqstp
->
rq_res
.
buflen
=
PAGE_SIZE
;
rqstp
->
rq_res
.
tail
[
0
].
iov_base
=
NULL
;
rqstp
->
rq_res
.
tail
[
0
].
iov_len
=
0
;
rqstp
->
rq_xid
=
svc_getu32
(
argv
);
dir
=
svc_getnl
(
argv
);
if
(
dir
!=
0
)
{
/* direction != CALL */
svc_printk
(
rqstp
,
"bad direction %d, dropping request
\n
"
,
dir
);
serv
->
sv_stats
->
rpcbadfmt
++
;
svc_drop
(
rqstp
);
return
0
;
}
error
=
svc_process_common
(
rqstp
,
argv
,
resv
);
if
(
error
<=
0
)
return
error
;
return
svc_send
(
rqstp
);
}
#if defined(CONFIG_NFS_V4_1)
/*
* Process a backchannel RPC request that arrived over an existing
* outbound connection
*/
int
bc_svc_process
(
struct
svc_serv
*
serv
,
struct
rpc_rqst
*
req
,
struct
svc_rqst
*
rqstp
)
{
struct
kvec
*
argv
=
&
rqstp
->
rq_arg
.
head
[
0
];
struct
kvec
*
resv
=
&
rqstp
->
rq_res
.
head
[
0
];
int
error
;
/* Build the svc_rqst used by the common processing routine */
rqstp
->
rq_xprt
=
serv
->
bc_xprt
;
rqstp
->
rq_xid
=
req
->
rq_xid
;
rqstp
->
rq_prot
=
req
->
rq_xprt
->
prot
;
rqstp
->
rq_server
=
serv
;
rqstp
->
rq_addrlen
=
sizeof
(
req
->
rq_xprt
->
addr
);
memcpy
(
&
rqstp
->
rq_addr
,
&
req
->
rq_xprt
->
addr
,
rqstp
->
rq_addrlen
);
memcpy
(
&
rqstp
->
rq_arg
,
&
req
->
rq_rcv_buf
,
sizeof
(
rqstp
->
rq_arg
));
memcpy
(
&
rqstp
->
rq_res
,
&
req
->
rq_snd_buf
,
sizeof
(
rqstp
->
rq_res
));
/* reset result send buffer "put" position */
resv
->
iov_len
=
0
;
if
(
rqstp
->
rq_prot
!=
IPPROTO_TCP
)
{
printk
(
KERN_ERR
"No support for Non-TCP transports!
\n
"
);
BUG
();
}
/*
* Skip the next two words because they've already been
* processed in the trasport
*/
svc_getu32
(
argv
);
/* XID */
svc_getnl
(
argv
);
/* CALLDIR */
error
=
svc_process_common
(
rqstp
,
argv
,
resv
);
if
(
error
<=
0
)
return
error
;
memcpy
(
&
req
->
rq_snd_buf
,
&
rqstp
->
rq_res
,
sizeof
(
req
->
rq_snd_buf
));
return
bc_send
(
req
);
}
EXPORT_SYMBOL
(
bc_svc_process
);
#endif
/* CONFIG_NFS_V4_1 */
/*
* Return (transport-specific) limit on the rpc payload.
*/
...
...
net/sunrpc/svcsock.c
View file @
301933a0
...
...
@@ -1327,3 +1327,42 @@ static void svc_sock_free(struct svc_xprt *xprt)
sock_release
(
svsk
->
sk_sock
);
kfree
(
svsk
);
}
/*
* Create a svc_xprt.
*
* For internal use only (e.g. nfsv4.1 backchannel).
* Callers should typically use the xpo_create() method.
*/
struct
svc_xprt
*
svc_sock_create
(
struct
svc_serv
*
serv
,
int
prot
)
{
struct
svc_sock
*
svsk
;
struct
svc_xprt
*
xprt
=
NULL
;
dprintk
(
"svc: %s
\n
"
,
__func__
);
svsk
=
kzalloc
(
sizeof
(
*
svsk
),
GFP_KERNEL
);
if
(
!
svsk
)
goto
out
;
xprt
=
&
svsk
->
sk_xprt
;
if
(
prot
==
IPPROTO_TCP
)
svc_xprt_init
(
&
svc_tcp_class
,
xprt
,
serv
);
else
if
(
prot
==
IPPROTO_UDP
)
svc_xprt_init
(
&
svc_udp_class
,
xprt
,
serv
);
else
BUG
();
out:
dprintk
(
"svc: %s return %p
\n
"
,
__func__
,
xprt
);
return
xprt
;
}
EXPORT_SYMBOL_GPL
(
svc_sock_create
);
/*
* Destroy a svc_sock.
*/
void
svc_sock_destroy
(
struct
svc_xprt
*
xprt
)
{
if
(
xprt
)
kfree
(
container_of
(
xprt
,
struct
svc_sock
,
sk_xprt
));
}
EXPORT_SYMBOL_GPL
(
svc_sock_destroy
);
net/sunrpc/xprt.c
View file @
301933a0
...
...
@@ -12,8 +12,9 @@
* - Next, the caller puts together the RPC message, stuffs it into
* the request struct, and calls xprt_transmit().
* - xprt_transmit sends the message and installs the caller on the
* transport's wait list. At the same time, it installs a timer that
* is run after the packet's timeout has expired.
* transport's wait list. At the same time, if a reply is expected,
* it installs a timer that is run after the packet's timeout has
* expired.
* - When a packet arrives, the data_ready handler walks the list of
* pending requests for that transport. If a matching XID is found, the
* caller is woken up, and the timer removed.
...
...
@@ -46,6 +47,8 @@
#include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/metrics.h>
#include "sunrpc.h"
/*
* Local variables
*/
...
...
@@ -192,8 +195,8 @@ EXPORT_SYMBOL_GPL(xprt_load_transport);
*/
int
xprt_reserve_xprt
(
struct
rpc_task
*
task
)
{
struct
rpc_xprt
*
xprt
=
task
->
tk_xprt
;
struct
rpc_rqst
*
req
=
task
->
tk_rqstp
;
struct
rpc_xprt
*
xprt
=
req
->
rq_xprt
;
if
(
test_and_set_bit
(
XPRT_LOCKED
,
&
xprt
->
state
))
{
if
(
task
==
xprt
->
snd_task
)
...
...
@@ -803,9 +806,10 @@ void xprt_complete_rqst(struct rpc_task *task, int copied)
list_del_init
(
&
req
->
rq_list
);
req
->
rq_private_buf
.
len
=
copied
;
/* Ensure all writes are done before we update req->rq_received */
/* Ensure all writes are done before we update */
/* req->rq_reply_bytes_recvd */
smp_wmb
();
req
->
rq_re
ceive
d
=
copied
;
req
->
rq_re
ply_bytes_recv
d
=
copied
;
rpc_wake_up_queued_task
(
&
xprt
->
pending
,
task
);
}
EXPORT_SYMBOL_GPL
(
xprt_complete_rqst
);
...
...
@@ -820,7 +824,7 @@ static void xprt_timer(struct rpc_task *task)
dprintk
(
"RPC: %5u xprt_timer
\n
"
,
task
->
tk_pid
);
spin_lock_bh
(
&
xprt
->
transport_lock
);
if
(
!
req
->
rq_re
ceive
d
)
{
if
(
!
req
->
rq_re
ply_bytes_recv
d
)
{
if
(
xprt
->
ops
->
timer
)
xprt
->
ops
->
timer
(
task
);
}
else
...
...
@@ -842,8 +846,8 @@ int xprt_prepare_transmit(struct rpc_task *task)
dprintk
(
"RPC: %5u xprt_prepare_transmit
\n
"
,
task
->
tk_pid
);
spin_lock_bh
(
&
xprt
->
transport_lock
);
if
(
req
->
rq_re
ceive
d
&&
!
req
->
rq_bytes_sent
)
{
err
=
req
->
rq_re
ceive
d
;
if
(
req
->
rq_re
ply_bytes_recv
d
&&
!
req
->
rq_bytes_sent
)
{
err
=
req
->
rq_re
ply_bytes_recv
d
;
goto
out_unlock
;
}
if
(
!
xprt
->
ops
->
reserve_xprt
(
task
))
...
...
@@ -855,7 +859,7 @@ int xprt_prepare_transmit(struct rpc_task *task)
void
xprt_end_transmit
(
struct
rpc_task
*
task
)
{
xprt_release_write
(
task
->
tk_xprt
,
task
);
xprt_release_write
(
task
->
tk_
rqstp
->
rq_
xprt
,
task
);
}
/**
...
...
@@ -872,8 +876,11 @@ void xprt_transmit(struct rpc_task *task)
dprintk
(
"RPC: %5u xprt_transmit(%u)
\n
"
,
task
->
tk_pid
,
req
->
rq_slen
);
if
(
!
req
->
rq_received
)
{
if
(
list_empty
(
&
req
->
rq_list
))
{
if
(
!
req
->
rq_reply_bytes_recvd
)
{
if
(
list_empty
(
&
req
->
rq_list
)
&&
rpc_reply_expected
(
task
))
{
/*
* Add to the list only if we're expecting a reply
*/
spin_lock_bh
(
&
xprt
->
transport_lock
);
/* Update the softirq receive buffer */
memcpy
(
&
req
->
rq_private_buf
,
&
req
->
rq_rcv_buf
,
...
...
@@ -908,8 +915,13 @@ void xprt_transmit(struct rpc_task *task)
/* Don't race with disconnect */
if
(
!
xprt_connected
(
xprt
))
task
->
tk_status
=
-
ENOTCONN
;
else
if
(
!
req
->
rq_received
)
else
if
(
!
req
->
rq_reply_bytes_recvd
&&
rpc_reply_expected
(
task
))
{
/*
* Sleep on the pending queue since
* we're expecting a reply.
*/
rpc_sleep_on
(
&
xprt
->
pending
,
task
,
xprt_timer
);
}
spin_unlock_bh
(
&
xprt
->
transport_lock
);
}
...
...
@@ -982,11 +994,17 @@ static void xprt_request_init(struct rpc_task *task, struct rpc_xprt *xprt)
*/
void
xprt_release
(
struct
rpc_task
*
task
)
{
struct
rpc_xprt
*
xprt
=
task
->
tk_xprt
;
struct
rpc_xprt
*
xprt
;
struct
rpc_rqst
*
req
;
int
is_bc_request
;
if
(
!
(
req
=
task
->
tk_rqstp
))
return
;
/* Preallocated backchannel request? */
is_bc_request
=
bc_prealloc
(
req
);
xprt
=
req
->
rq_xprt
;
rpc_count_iostats
(
task
);
spin_lock_bh
(
&
xprt
->
transport_lock
);
xprt
->
ops
->
release_xprt
(
xprt
,
task
);
...
...
@@ -999,10 +1017,19 @@ void xprt_release(struct rpc_task *task)
mod_timer
(
&
xprt
->
timer
,
xprt
->
last_used
+
xprt
->
idle_timeout
);
spin_unlock_bh
(
&
xprt
->
transport_lock
);
if
(
!
bc_prealloc
(
req
))
xprt
->
ops
->
buf_free
(
req
->
rq_buffer
);
task
->
tk_rqstp
=
NULL
;
if
(
req
->
rq_release_snd_buf
)
req
->
rq_release_snd_buf
(
req
);
/*
* Early exit if this is a backchannel preallocated request.
* There is no need to have it added to the RPC slot list.
*/
if
(
is_bc_request
)
return
;
memset
(
req
,
0
,
sizeof
(
*
req
));
/* mark unused */
dprintk
(
"RPC: %5u release request %p
\n
"
,
task
->
tk_pid
,
req
);
...
...
@@ -1049,6 +1076,11 @@ struct rpc_xprt *xprt_create_transport(struct xprt_create *args)
INIT_LIST_HEAD
(
&
xprt
->
free
);
INIT_LIST_HEAD
(
&
xprt
->
recv
);
#if defined(CONFIG_NFS_V4_1)
spin_lock_init
(
&
xprt
->
bc_pa_lock
);
INIT_LIST_HEAD
(
&
xprt
->
bc_pa_list
);
#endif
/* CONFIG_NFS_V4_1 */
INIT_WORK
(
&
xprt
->
task_cleanup
,
xprt_autoclose
);
setup_timer
(
&
xprt
->
timer
,
xprt_init_autodisconnect
,
(
unsigned
long
)
xprt
);
...
...
net/sunrpc/xprtsock.c
View file @
301933a0
...
...
@@ -34,6 +34,9 @@
#include <linux/sunrpc/sched.h>
#include <linux/sunrpc/xprtsock.h>
#include <linux/file.h>
#ifdef CONFIG_NFS_V4_1
#include <linux/sunrpc/bc_xprt.h>
#endif
#include <net/sock.h>
#include <net/checksum.h>
...
...
@@ -270,6 +273,13 @@ struct sock_xprt {
#define TCP_RCV_COPY_FRAGHDR (1UL << 1)
#define TCP_RCV_COPY_XID (1UL << 2)
#define TCP_RCV_COPY_DATA (1UL << 3)
#define TCP_RCV_READ_CALLDIR (1UL << 4)
#define TCP_RCV_COPY_CALLDIR (1UL << 5)
/*
* TCP RPC flags
*/
#define TCP_RPC_REPLY (1UL << 6)
static
inline
struct
sockaddr
*
xs_addr
(
struct
rpc_xprt
*
xprt
)
{
...
...
@@ -956,7 +966,7 @@ static inline void xs_tcp_read_fraghdr(struct rpc_xprt *xprt, struct xdr_skb_rea
transport
->
tcp_offset
=
0
;
/* Sanity check of the record length */
if
(
unlikely
(
transport
->
tcp_reclen
<
4
))
{
if
(
unlikely
(
transport
->
tcp_reclen
<
8
))
{
dprintk
(
"RPC: invalid TCP record fragment length
\n
"
);
xprt_force_disconnect
(
xprt
);
return
;
...
...
@@ -991,33 +1001,77 @@ static inline void xs_tcp_read_xid(struct sock_xprt *transport, struct xdr_skb_r
if
(
used
!=
len
)
return
;
transport
->
tcp_flags
&=
~
TCP_RCV_COPY_XID
;
transport
->
tcp_flags
|=
TCP_RCV_
COPY_DATA
;
transport
->
tcp_flags
|=
TCP_RCV_
READ_CALLDIR
;
transport
->
tcp_copied
=
4
;
dprintk
(
"RPC: reading reply for XID %08x
\n
"
,
dprintk
(
"RPC: reading %s XID %08x
\n
"
,
(
transport
->
tcp_flags
&
TCP_RPC_REPLY
)
?
"reply for"
:
"request with"
,
ntohl
(
transport
->
tcp_xid
));
xs_tcp_check_fraghdr
(
transport
);
}
static
inline
void
xs_tcp_read_request
(
struct
rpc_xprt
*
xprt
,
struct
xdr_skb_reader
*
desc
)
static
inline
void
xs_tcp_read_calldir
(
struct
sock_xprt
*
transport
,
struct
xdr_skb_reader
*
desc
)
{
struct
sock_xprt
*
transport
=
container_of
(
xprt
,
struct
sock_xprt
,
xprt
);
struct
rpc_rqst
*
req
;
size_t
len
,
used
;
u32
offset
;
__be32
calldir
;
/*
* We want transport->tcp_offset to be 8 at the end of this routine
* (4 bytes for the xid and 4 bytes for the call/reply flag).
* When this function is called for the first time,
* transport->tcp_offset is 4 (after having already read the xid).
*/
offset
=
transport
->
tcp_offset
-
sizeof
(
transport
->
tcp_xid
);
len
=
sizeof
(
calldir
)
-
offset
;
dprintk
(
"RPC: reading CALL/REPLY flag (%Zu bytes)
\n
"
,
len
);
used
=
xdr_skb_read_bits
(
desc
,
&
calldir
,
len
);
transport
->
tcp_offset
+=
used
;
if
(
used
!=
len
)
return
;
transport
->
tcp_flags
&=
~
TCP_RCV_READ_CALLDIR
;
transport
->
tcp_flags
|=
TCP_RCV_COPY_CALLDIR
;
transport
->
tcp_flags
|=
TCP_RCV_COPY_DATA
;
/*
* We don't yet have the XDR buffer, so we will write the calldir
* out after we get the buffer from the 'struct rpc_rqst'
*/
if
(
ntohl
(
calldir
)
==
RPC_REPLY
)
transport
->
tcp_flags
|=
TCP_RPC_REPLY
;
else
transport
->
tcp_flags
&=
~
TCP_RPC_REPLY
;
dprintk
(
"RPC: reading %s CALL/REPLY flag %08x
\n
"
,
(
transport
->
tcp_flags
&
TCP_RPC_REPLY
)
?
"reply for"
:
"request with"
,
calldir
);
xs_tcp_check_fraghdr
(
transport
);
}
static
inline
void
xs_tcp_read_common
(
struct
rpc_xprt
*
xprt
,
struct
xdr_skb_reader
*
desc
,
struct
rpc_rqst
*
req
)
{
struct
sock_xprt
*
transport
=
container_of
(
xprt
,
struct
sock_xprt
,
xprt
);
struct
xdr_buf
*
rcvbuf
;
size_t
len
;
ssize_t
r
;
/* Find and lock the request corresponding to this xid */
spin_lock
(
&
xprt
->
transport_lock
);
req
=
xprt_lookup_rqst
(
xprt
,
transport
->
tcp_xid
);
if
(
!
req
)
{
transport
->
tcp_flags
&=
~
TCP_RCV_COPY_DATA
;
dprintk
(
"RPC: XID %08x request not found!
\n
"
,
ntohl
(
transport
->
tcp_xid
));
spin_unlock
(
&
xprt
->
transport_lock
);
return
;
rcvbuf
=
&
req
->
rq_private_buf
;
if
(
transport
->
tcp_flags
&
TCP_RCV_COPY_CALLDIR
)
{
/*
* Save the RPC direction in the XDR buffer
*/
__be32
calldir
=
transport
->
tcp_flags
&
TCP_RPC_REPLY
?
htonl
(
RPC_REPLY
)
:
0
;
memcpy
(
rcvbuf
->
head
[
0
].
iov_base
+
transport
->
tcp_copied
,
&
calldir
,
sizeof
(
calldir
));
transport
->
tcp_copied
+=
sizeof
(
calldir
);
transport
->
tcp_flags
&=
~
TCP_RCV_COPY_CALLDIR
;
}
rcvbuf
=
&
req
->
rq_private_buf
;
len
=
desc
->
count
;
if
(
len
>
transport
->
tcp_reclen
-
transport
->
tcp_offset
)
{
struct
xdr_skb_reader
my_desc
;
...
...
@@ -1054,7 +1108,7 @@ static inline void xs_tcp_read_request(struct rpc_xprt *xprt, struct xdr_skb_rea
"tcp_offset = %u, tcp_reclen = %u
\n
"
,
xprt
,
transport
->
tcp_copied
,
transport
->
tcp_offset
,
transport
->
tcp_reclen
);
goto
out
;
return
;
}
dprintk
(
"RPC: XID %08x read %Zd bytes
\n
"
,
...
...
@@ -1070,11 +1124,125 @@ static inline void xs_tcp_read_request(struct rpc_xprt *xprt, struct xdr_skb_rea
transport
->
tcp_flags
&=
~
TCP_RCV_COPY_DATA
;
}
out:
return
;
}
/*
* Finds the request corresponding to the RPC xid and invokes the common
* tcp read code to read the data.
*/
static
inline
int
xs_tcp_read_reply
(
struct
rpc_xprt
*
xprt
,
struct
xdr_skb_reader
*
desc
)
{
struct
sock_xprt
*
transport
=
container_of
(
xprt
,
struct
sock_xprt
,
xprt
);
struct
rpc_rqst
*
req
;
dprintk
(
"RPC: read reply XID %08x
\n
"
,
ntohl
(
transport
->
tcp_xid
));
/* Find and lock the request corresponding to this xid */
spin_lock
(
&
xprt
->
transport_lock
);
req
=
xprt_lookup_rqst
(
xprt
,
transport
->
tcp_xid
);
if
(
!
req
)
{
dprintk
(
"RPC: XID %08x request not found!
\n
"
,
ntohl
(
transport
->
tcp_xid
));
spin_unlock
(
&
xprt
->
transport_lock
);
return
-
1
;
}
xs_tcp_read_common
(
xprt
,
desc
,
req
);
if
(
!
(
transport
->
tcp_flags
&
TCP_RCV_COPY_DATA
))
xprt_complete_rqst
(
req
->
rq_task
,
transport
->
tcp_copied
);
spin_unlock
(
&
xprt
->
transport_lock
);
return
0
;
}
#if defined(CONFIG_NFS_V4_1)
/*
* Obtains an rpc_rqst previously allocated and invokes the common
* tcp read code to read the data. The result is placed in the callback
* queue.
* If we're unable to obtain the rpc_rqst we schedule the closing of the
* connection and return -1.
*/
static
inline
int
xs_tcp_read_callback
(
struct
rpc_xprt
*
xprt
,
struct
xdr_skb_reader
*
desc
)
{
struct
sock_xprt
*
transport
=
container_of
(
xprt
,
struct
sock_xprt
,
xprt
);
struct
rpc_rqst
*
req
;
req
=
xprt_alloc_bc_request
(
xprt
);
if
(
req
==
NULL
)
{
printk
(
KERN_WARNING
"Callback slot table overflowed
\n
"
);
xprt_force_disconnect
(
xprt
);
return
-
1
;
}
req
->
rq_xid
=
transport
->
tcp_xid
;
dprintk
(
"RPC: read callback XID %08x
\n
"
,
ntohl
(
req
->
rq_xid
));
xs_tcp_read_common
(
xprt
,
desc
,
req
);
if
(
!
(
transport
->
tcp_flags
&
TCP_RCV_COPY_DATA
))
{
struct
svc_serv
*
bc_serv
=
xprt
->
bc_serv
;
/*
* Add callback request to callback list. The callback
* service sleeps on the sv_cb_waitq waiting for new
* requests. Wake it up after adding enqueing the
* request.
*/
dprintk
(
"RPC: add callback request to list
\n
"
);
spin_lock
(
&
bc_serv
->
sv_cb_lock
);
list_add
(
&
req
->
rq_bc_list
,
&
bc_serv
->
sv_cb_list
);
spin_unlock
(
&
bc_serv
->
sv_cb_lock
);
wake_up
(
&
bc_serv
->
sv_cb_waitq
);
}
req
->
rq_private_buf
.
len
=
transport
->
tcp_copied
;
return
0
;
}
static
inline
int
_xs_tcp_read_data
(
struct
rpc_xprt
*
xprt
,
struct
xdr_skb_reader
*
desc
)
{
struct
sock_xprt
*
transport
=
container_of
(
xprt
,
struct
sock_xprt
,
xprt
);
return
(
transport
->
tcp_flags
&
TCP_RPC_REPLY
)
?
xs_tcp_read_reply
(
xprt
,
desc
)
:
xs_tcp_read_callback
(
xprt
,
desc
);
}
#else
static
inline
int
_xs_tcp_read_data
(
struct
rpc_xprt
*
xprt
,
struct
xdr_skb_reader
*
desc
)
{
return
xs_tcp_read_reply
(
xprt
,
desc
);
}
#endif
/* CONFIG_NFS_V4_1 */
/*
* Read data off the transport. This can be either an RPC_CALL or an
* RPC_REPLY. Relay the processing to helper functions.
*/
static
void
xs_tcp_read_data
(
struct
rpc_xprt
*
xprt
,
struct
xdr_skb_reader
*
desc
)
{
struct
sock_xprt
*
transport
=
container_of
(
xprt
,
struct
sock_xprt
,
xprt
);
if
(
_xs_tcp_read_data
(
xprt
,
desc
)
==
0
)
xs_tcp_check_fraghdr
(
transport
);
else
{
/*
* The transport_lock protects the request handling.
* There's no need to hold it to update the tcp_flags.
*/
transport
->
tcp_flags
&=
~
TCP_RCV_COPY_DATA
;
}
}
static
inline
void
xs_tcp_read_discard
(
struct
sock_xprt
*
transport
,
struct
xdr_skb_reader
*
desc
)
...
...
@@ -1114,9 +1282,14 @@ static int xs_tcp_data_recv(read_descriptor_t *rd_desc, struct sk_buff *skb, uns
xs_tcp_read_xid
(
transport
,
&
desc
);
continue
;
}
/* Read in the call/reply flag */
if
(
transport
->
tcp_flags
&
TCP_RCV_READ_CALLDIR
)
{
xs_tcp_read_calldir
(
transport
,
&
desc
);
continue
;
}
/* Read in the request data */
if
(
transport
->
tcp_flags
&
TCP_RCV_COPY_DATA
)
{
xs_tcp_read_
request
(
xprt
,
&
desc
);
xs_tcp_read_
data
(
xprt
,
&
desc
);
continue
;
}
/* Skip over any trailing bytes on short reads */
...
...
@@ -2010,6 +2183,9 @@ static struct rpc_xprt_ops xs_tcp_ops = {
.
buf_free
=
rpc_free
,
.
send_request
=
xs_tcp_send_request
,
.
set_retrans_timeout
=
xprt_set_retrans_timeout_def
,
#if defined(CONFIG_NFS_V4_1)
.
release_request
=
bc_release_request
,
#endif
/* CONFIG_NFS_V4_1 */
.
close
=
xs_tcp_close
,
.
destroy
=
xs_destroy
,
.
print_stats
=
xs_tcp_print_stats
,
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment