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
dce9f3bf
Commit
dce9f3bf
authored
Feb 07, 2004
by
Trond Myklebust
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
NFSv4: Basic code for recovering file OPEN state after a server
reboot.
parent
e85c40cd
Changes
4
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
317 additions
and
63 deletions
+317
-63
fs/nfs/inode.c
fs/nfs/inode.c
+2
-0
fs/nfs/nfs4proc.c
fs/nfs/nfs4proc.c
+193
-42
fs/nfs/nfs4state.c
fs/nfs/nfs4state.c
+110
-19
include/linux/nfs_fs.h
include/linux/nfs_fs.h
+12
-2
No files found.
fs/nfs/inode.c
View file @
dce9f3bf
...
@@ -1448,6 +1448,8 @@ static int nfs4_fill_super(struct super_block *sb, struct nfs4_mount_data *data,
...
@@ -1448,6 +1448,8 @@ static int nfs4_fill_super(struct super_block *sb, struct nfs4_mount_data *data,
clp
->
cl_cred
=
rpcauth_lookupcred
(
clnt
->
cl_auth
,
0
);
clp
->
cl_cred
=
rpcauth_lookupcred
(
clnt
->
cl_auth
,
0
);
memcpy
(
clp
->
cl_ipaddr
,
server
->
ip_addr
,
sizeof
(
clp
->
cl_ipaddr
));
memcpy
(
clp
->
cl_ipaddr
,
server
->
ip_addr
,
sizeof
(
clp
->
cl_ipaddr
));
}
}
if
(
list_empty
(
&
clp
->
cl_superblocks
))
clear_bit
(
NFS4CLNT_OK
,
&
clp
->
cl_state
);
list_add_tail
(
&
server
->
nfs4_siblings
,
&
clp
->
cl_superblocks
);
list_add_tail
(
&
server
->
nfs4_siblings
,
&
clp
->
cl_superblocks
);
clnt
=
rpc_clone_client
(
clp
->
cl_rpcclient
);
clnt
=
rpc_clone_client
(
clp
->
cl_rpcclient
);
server
->
nfs4_state
=
clp
;
server
->
nfs4_state
=
clp
;
...
...
fs/nfs/nfs4proc.c
View file @
dce9f3bf
This diff is collapsed.
Click to expand it.
fs/nfs/nfs4state.c
View file @
dce9f3bf
...
@@ -56,6 +56,7 @@ nfs4_stateid one_stateid =
...
@@ -56,6 +56,7 @@ nfs4_stateid one_stateid =
static
LIST_HEAD
(
nfs4_clientid_list
);
static
LIST_HEAD
(
nfs4_clientid_list
);
static
void
nfs4_recover_state
(
void
*
);
extern
void
nfs4_renew_state
(
void
*
);
extern
void
nfs4_renew_state
(
void
*
);
void
void
...
@@ -98,9 +99,12 @@ nfs4_alloc_client(struct in_addr *addr)
...
@@ -98,9 +99,12 @@ nfs4_alloc_client(struct in_addr *addr)
INIT_LIST_HEAD
(
&
clp
->
cl_unused
);
INIT_LIST_HEAD
(
&
clp
->
cl_unused
);
spin_lock_init
(
&
clp
->
cl_lock
);
spin_lock_init
(
&
clp
->
cl_lock
);
atomic_set
(
&
clp
->
cl_count
,
1
);
atomic_set
(
&
clp
->
cl_count
,
1
);
INIT_WORK
(
&
clp
->
cl_recoverd
,
nfs4_recover_state
,
clp
);
INIT_WORK
(
&
clp
->
cl_renewd
,
nfs4_renew_state
,
clp
);
INIT_WORK
(
&
clp
->
cl_renewd
,
nfs4_renew_state
,
clp
);
INIT_LIST_HEAD
(
&
clp
->
cl_superblocks
);
INIT_LIST_HEAD
(
&
clp
->
cl_superblocks
);
clp
->
cl_state
=
NFS4CLNT_NEW
;
init_waitqueue_head
(
&
clp
->
cl_waitq
);
INIT_RPC_WAITQ
(
&
clp
->
cl_rpcwaitq
,
"NFS4 client"
);
clp
->
cl_state
=
1
<<
NFS4CLNT_NEW
;
}
}
return
clp
;
return
clp
;
}
}
...
@@ -155,6 +159,9 @@ nfs4_put_client(struct nfs4_client *clp)
...
@@ -155,6 +159,9 @@ nfs4_put_client(struct nfs4_client *clp)
return
;
return
;
list_del
(
&
clp
->
cl_servers
);
list_del
(
&
clp
->
cl_servers
);
spin_unlock
(
&
state_spinlock
);
spin_unlock
(
&
state_spinlock
);
BUG_ON
(
!
list_empty
(
&
clp
->
cl_superblocks
));
wake_up_all
(
&
clp
->
cl_waitq
);
rpc_wake_up
(
&
clp
->
cl_rpcwaitq
);
nfs4_kill_renewd
(
clp
);
nfs4_kill_renewd
(
clp
);
nfs4_free_client
(
clp
);
nfs4_free_client
(
clp
);
}
}
...
@@ -175,6 +182,7 @@ nfs4_client_grab_unused(struct nfs4_client *clp, struct rpc_cred *cred)
...
@@ -175,6 +182,7 @@ nfs4_client_grab_unused(struct nfs4_client *clp, struct rpc_cred *cred)
atomic_inc
(
&
sp
->
so_count
);
atomic_inc
(
&
sp
->
so_count
);
sp
->
so_cred
=
cred
;
sp
->
so_cred
=
cred
;
list_move
(
&
sp
->
so_list
,
&
clp
->
cl_state_owners
);
list_move
(
&
sp
->
so_list
,
&
clp
->
cl_state_owners
);
sp
->
so_generation
=
clp
->
cl_generation
;
clp
->
cl_nunused
--
;
clp
->
cl_nunused
--
;
}
}
return
sp
;
return
sp
;
...
@@ -215,13 +223,17 @@ nfs4_get_state_owner(struct nfs_server *server, struct rpc_cred *cred)
...
@@ -215,13 +223,17 @@ nfs4_get_state_owner(struct nfs_server *server, struct rpc_cred *cred)
new
->
so_client
=
clp
;
new
->
so_client
=
clp
;
new
->
so_id
=
nfs4_alloc_lockowner_id
(
clp
);
new
->
so_id
=
nfs4_alloc_lockowner_id
(
clp
);
new
->
so_cred
=
cred
;
new
->
so_cred
=
cred
;
new
->
so_generation
=
clp
->
cl_generation
;
sp
=
new
;
sp
=
new
;
new
=
NULL
;
new
=
NULL
;
}
}
spin_unlock
(
&
clp
->
cl_lock
);
spin_unlock
(
&
clp
->
cl_lock
);
if
(
new
)
if
(
new
)
kfree
(
new
);
kfree
(
new
);
if
(
!
sp
)
if
(
sp
)
{
if
(
!
test_bit
(
NFS4CLNT_OK
,
&
clp
->
cl_state
))
nfs4_wait_clnt_recover
(
server
->
client
,
clp
);
}
else
put_rpccred
(
cred
);
put_rpccred
(
cred
);
return
sp
;
return
sp
;
}
}
...
@@ -353,6 +365,7 @@ nfs4_put_open_state(struct nfs4_state *state)
...
@@ -353,6 +365,7 @@ nfs4_put_open_state(struct nfs4_state *state)
{
{
struct
inode
*
inode
=
state
->
inode
;
struct
inode
*
inode
=
state
->
inode
;
struct
nfs4_state_owner
*
owner
=
state
->
owner
;
struct
nfs4_state_owner
*
owner
=
state
->
owner
;
int
status
=
0
;
if
(
!
atomic_dec_and_lock
(
&
state
->
count
,
&
inode
->
i_lock
))
if
(
!
atomic_dec_and_lock
(
&
state
->
count
,
&
inode
->
i_lock
))
return
;
return
;
...
@@ -360,8 +373,16 @@ nfs4_put_open_state(struct nfs4_state *state)
...
@@ -360,8 +373,16 @@ nfs4_put_open_state(struct nfs4_state *state)
spin_unlock
(
&
inode
->
i_lock
);
spin_unlock
(
&
inode
->
i_lock
);
down
(
&
owner
->
so_sema
);
down
(
&
owner
->
so_sema
);
list_del
(
&
state
->
open_states
);
list_del
(
&
state
->
open_states
);
if
(
state
->
state
!=
0
)
if
(
state
->
state
!=
0
)
{
nfs4_do_close
(
inode
,
state
);
do
{
status
=
nfs4_do_close
(
inode
,
state
);
if
(
!
status
)
break
;
up
(
&
owner
->
so_sema
);
status
=
nfs4_handle_error
(
NFS_SERVER
(
inode
),
status
);
down
(
&
owner
->
so_sema
);
}
while
(
!
status
);
}
up
(
&
owner
->
so_sema
);
up
(
&
owner
->
so_sema
);
iput
(
inode
);
iput
(
inode
);
nfs4_free_open_state
(
state
);
nfs4_free_open_state
(
state
);
...
@@ -392,41 +413,81 @@ struct reclaimer_args {
...
@@ -392,41 +413,81 @@ struct reclaimer_args {
* State recovery routine
* State recovery routine
*/
*/
void
void
nfs4_recover_state
(
struct
nfs4_client
*
clp
)
nfs4_recover_state
(
void
*
data
)
{
{
struct
nfs4_client
*
clp
=
(
struct
nfs4_client
*
)
data
;
struct
reclaimer_args
args
=
{
struct
reclaimer_args
args
=
{
.
clp
=
clp
,
.
clp
=
clp
,
};
};
might_sleep
();
init_completion
(
&
args
.
complete
);
init_completion
(
&
args
.
complete
);
down_read
(
&
clp
->
cl_sem
);
down_read
(
&
clp
->
cl_sem
);
if
(
kernel_thread
(
reclaimer
,
&
args
,
CLONE_KERNEL
)
<
0
)
if
(
test_and_set_bit
(
NFS4CLNT_SETUP_STATE
,
&
clp
->
cl_state
)
)
goto
out_failed
;
goto
out_failed
;
if
(
kernel_thread
(
reclaimer
,
&
args
,
CLONE_KERNEL
)
<
0
)
goto
out_failed_clear
;
wait_for_completion
(
&
args
.
complete
);
wait_for_completion
(
&
args
.
complete
);
return
;
return
;
out_failed_clear:
smp_mb__before_clear_bit
();
clear_bit
(
NFS4CLNT_SETUP_STATE
,
&
clp
->
cl_state
);
smp_mb__after_clear_bit
();
wake_up_all
(
&
clp
->
cl_waitq
);
rpc_wake_up
(
&
clp
->
cl_rpcwaitq
);
out_failed:
out_failed:
up_read
(
&
clp
->
cl_sem
);
up_read
(
&
clp
->
cl_sem
);
}
}
static
void
/*
* Schedule a state recovery attempt
*/
void
nfs4_schedule_state_recovery
(
struct
nfs4_client
*
clp
)
{
if
(
!
clp
)
return
;
smp_mb__before_clear_bit
();
clear_bit
(
NFS4CLNT_OK
,
&
clp
->
cl_state
);
smp_mb__after_clear_bit
();
schedule_work
(
&
clp
->
cl_recoverd
);
}
static
int
nfs4_reclaim_open_state
(
struct
nfs4_state_owner
*
sp
)
nfs4_reclaim_open_state
(
struct
nfs4_state_owner
*
sp
)
{
{
struct
nfs4_state
*
state
;
struct
nfs4_state
*
state
;
int
status
;
int
status
=
0
;
list_for_each_entry
(
state
,
&
sp
->
so_states
,
open_states
)
{
list_for_each_entry
(
state
,
&
sp
->
so_states
,
open_states
)
{
status
=
nfs4_open_reclaim
(
sp
,
state
);
status
=
nfs4_open_reclaim
(
sp
,
state
);
if
(
status
)
{
if
(
status
>=
0
)
/*
continue
;
* Open state on this file cannot be recovered
switch
(
status
)
{
* All we can do is revert to using the zero stateid.
default:
*/
printk
(
KERN_ERR
"%s: unhandled error %d. Zeroing state
\n
"
,
memset
(
state
->
stateid
.
data
,
0
,
__FUNCTION__
,
status
);
case
-
NFS4ERR_EXPIRED
:
case
-
NFS4ERR_NO_GRACE
:
case
-
NFS4ERR_RECLAIM_BAD
:
case
-
NFS4ERR_RECLAIM_CONFLICT
:
/*
* Open state on this file cannot be recovered
* All we can do is revert to using the zero stateid.
*/
memset
(
state
->
stateid
.
data
,
0
,
sizeof
(
state
->
stateid
.
data
));
sizeof
(
state
->
stateid
.
data
));
/* Mark the file as being 'closed' */
/* Mark the file as being 'closed' */
state
->
state
=
0
;
state
->
state
=
0
;
break
;
case
-
NFS4ERR_STALE_CLIENTID
:
goto
out_err
;
}
}
}
}
return
0
;
out_err:
return
status
;
}
}
static
int
static
int
...
@@ -435,6 +496,7 @@ reclaimer(void *ptr)
...
@@ -435,6 +496,7 @@ reclaimer(void *ptr)
struct
reclaimer_args
*
args
=
(
struct
reclaimer_args
*
)
ptr
;
struct
reclaimer_args
*
args
=
(
struct
reclaimer_args
*
)
ptr
;
struct
nfs4_client
*
clp
=
args
->
clp
;
struct
nfs4_client
*
clp
=
args
->
clp
;
struct
nfs4_state_owner
*
sp
;
struct
nfs4_state_owner
*
sp
;
int
generation
;
int
status
;
int
status
;
daemonize
(
"%u.%u.%u.%u-reclaim"
,
NIPQUAD
(
clp
->
cl_addr
));
daemonize
(
"%u.%u.%u.%u-reclaim"
,
NIPQUAD
(
clp
->
cl_addr
));
...
@@ -445,29 +507,58 @@ reclaimer(void *ptr)
...
@@ -445,29 +507,58 @@ reclaimer(void *ptr)
/* Are there any NFS mounts out there? */
/* Are there any NFS mounts out there? */
if
(
list_empty
(
&
clp
->
cl_superblocks
))
if
(
list_empty
(
&
clp
->
cl_superblocks
))
goto
out
;
goto
out
;
if
(
!
test_bit
(
NFS4CLNT_NEW
,
&
clp
->
cl_state
))
{
status
=
nfs4_proc_renew
(
clp
);
if
(
status
==
0
)
{
set_bit
(
NFS4CLNT_OK
,
&
clp
->
cl_state
);
goto
out
;
}
}
status
=
nfs4_proc_setclientid
(
clp
,
0
,
0
);
status
=
nfs4_proc_setclientid
(
clp
,
0
,
0
);
if
(
status
)
if
(
status
)
goto
out_error
;
goto
out_error
;
status
=
nfs4_proc_setclientid_confirm
(
clp
);
status
=
nfs4_proc_setclientid_confirm
(
clp
);
if
(
status
)
if
(
status
)
goto
out_error
;
goto
out_error
;
generation
=
++
(
clp
->
cl_generation
);
clear_bit
(
NFS4CLNT_NEW
,
&
clp
->
cl_state
);
set_bit
(
NFS4CLNT_OK
,
&
clp
->
cl_state
);
up_read
(
&
clp
->
cl_sem
);
nfs4_schedule_state_renewal
(
clp
);
restart_loop:
spin_lock
(
&
clp
->
cl_lock
);
spin_lock
(
&
clp
->
cl_lock
);
list_for_each_entry
(
sp
,
&
clp
->
cl_state_owners
,
so_list
)
{
list_for_each_entry
(
sp
,
&
clp
->
cl_state_owners
,
so_list
)
{
if
(
sp
->
so_generation
-
generation
<=
0
)
continue
;
atomic_inc
(
&
sp
->
so_count
);
atomic_inc
(
&
sp
->
so_count
);
spin_unlock
(
&
clp
->
cl_lock
);
spin_unlock
(
&
clp
->
cl_lock
);
down
(
&
sp
->
so_sema
);
down
(
&
sp
->
so_sema
);
nfs4_reclaim_open_state
(
sp
);
if
(
sp
->
so_generation
-
generation
<
0
)
{
smp_rmb
();
sp
->
so_generation
=
clp
->
cl_generation
;
status
=
nfs4_reclaim_open_state
(
sp
);
}
up
(
&
sp
->
so_sema
);
up
(
&
sp
->
so_sema
);
nfs4_put_state_owner
(
sp
);
nfs4_put_state_owner
(
sp
);
spin_lock
(
&
clp
->
cl_lock
);
if
(
status
<
0
)
{
if
(
status
==
-
NFS4ERR_STALE_CLIENTID
)
nfs4_schedule_state_recovery
(
clp
);
goto
out
;
}
goto
restart_loop
;
}
}
spin_unlock
(
&
clp
->
cl_lock
);
spin_unlock
(
&
clp
->
cl_lock
);
out:
out:
up_read
(
&
clp
->
cl_sem
);
smp_mb__before_clear_bit
();
clear_bit
(
NFS4CLNT_SETUP_STATE
,
&
clp
->
cl_state
);
smp_mb__after_clear_bit
();
wake_up_all
(
&
clp
->
cl_waitq
);
rpc_wake_up
(
&
clp
->
cl_rpcwaitq
);
return
0
;
return
0
;
out_error:
out_error:
printk
(
KERN_WARNING
"Error: state recovery failed on NFSv4 server %u.%u.%u.%u
\n
"
,
printk
(
KERN_WARNING
"Error: state recovery failed on NFSv4 server %u.%u.%u.%u
\n
"
,
NIPQUAD
(
clp
->
cl_addr
.
s_addr
));
NIPQUAD
(
clp
->
cl_addr
.
s_addr
));
up_read
(
&
clp
->
cl_sem
);
goto
out
;
goto
out
;
}
}
...
...
include/linux/nfs_fs.h
View file @
dce9f3bf
...
@@ -465,6 +465,7 @@ extern void * nfs_root_data(void);
...
@@ -465,6 +465,7 @@ extern void * nfs_root_data(void);
enum
nfs4_client_state
{
enum
nfs4_client_state
{
NFS4CLNT_OK
=
0
,
NFS4CLNT_OK
=
0
,
NFS4CLNT_NEW
,
NFS4CLNT_NEW
,
NFS4CLNT_SETUP_STATE
,
};
};
/*
/*
...
@@ -475,7 +476,8 @@ struct nfs4_client {
...
@@ -475,7 +476,8 @@ struct nfs4_client {
struct
in_addr
cl_addr
;
/* Server identifier */
struct
in_addr
cl_addr
;
/* Server identifier */
u64
cl_clientid
;
/* constant */
u64
cl_clientid
;
/* constant */
nfs4_verifier
cl_confirm
;
nfs4_verifier
cl_confirm
;
enum
nfs4_client_state
cl_state
;
unsigned
long
cl_state
;
long
cl_generation
;
u32
cl_lockowner_id
;
u32
cl_lockowner_id
;
...
@@ -499,6 +501,10 @@ struct nfs4_client {
...
@@ -499,6 +501,10 @@ struct nfs4_client {
unsigned
long
cl_lease_time
;
unsigned
long
cl_lease_time
;
unsigned
long
cl_last_renewal
;
unsigned
long
cl_last_renewal
;
struct
work_struct
cl_renewd
;
struct
work_struct
cl_renewd
;
struct
work_struct
cl_recoverd
;
wait_queue_head_t
cl_waitq
;
struct
rpc_wait_queue
cl_rpcwaitq
;
/* Our own IP address, as a null-terminated string.
/* Our own IP address, as a null-terminated string.
* This is used to generate the clientid, and the callback address.
* This is used to generate the clientid, and the callback address.
...
@@ -523,6 +529,7 @@ struct nfs4_state_owner {
...
@@ -523,6 +529,7 @@ struct nfs4_state_owner {
u32
so_seqid
;
/* protected by so_sema */
u32
so_seqid
;
/* protected by so_sema */
unsigned
int
so_flags
;
/* protected by so_sema */
unsigned
int
so_flags
;
/* protected by so_sema */
atomic_t
so_count
;
atomic_t
so_count
;
long
so_generation
;
struct
rpc_cred
*
so_cred
;
/* Associated cred */
struct
rpc_cred
*
so_cred
;
/* Associated cred */
struct
list_head
so_states
;
struct
list_head
so_states
;
...
@@ -556,7 +563,9 @@ extern int nfs4_proc_setclientid(struct nfs4_client *, u32, unsigned short);
...
@@ -556,7 +563,9 @@ extern int nfs4_proc_setclientid(struct nfs4_client *, u32, unsigned short);
extern
int
nfs4_proc_setclientid_confirm
(
struct
nfs4_client
*
);
extern
int
nfs4_proc_setclientid_confirm
(
struct
nfs4_client
*
);
extern
int
nfs4_open_reclaim
(
struct
nfs4_state_owner
*
,
struct
nfs4_state
*
);
extern
int
nfs4_open_reclaim
(
struct
nfs4_state_owner
*
,
struct
nfs4_state
*
);
extern
int
nfs4_proc_async_renew
(
struct
nfs4_client
*
);
extern
int
nfs4_proc_async_renew
(
struct
nfs4_client
*
);
extern
int
nfs4_proc_renew
(
struct
nfs4_client
*
);
extern
int
nfs4_do_close
(
struct
inode
*
,
struct
nfs4_state
*
);
extern
int
nfs4_do_close
(
struct
inode
*
,
struct
nfs4_state
*
);
extern
int
nfs4_wait_clnt_recover
(
struct
rpc_clnt
*
,
struct
nfs4_client
*
);
/* nfs4renewd.c */
/* nfs4renewd.c */
extern
void
nfs4_schedule_state_renewal
(
struct
nfs4_client
*
);
extern
void
nfs4_schedule_state_renewal
(
struct
nfs4_client
*
);
...
@@ -573,7 +582,8 @@ extern void nfs4_put_state_owner(struct nfs4_state_owner *);
...
@@ -573,7 +582,8 @@ extern void nfs4_put_state_owner(struct nfs4_state_owner *);
extern
struct
nfs4_state
*
nfs4_get_open_state
(
struct
inode
*
,
struct
nfs4_state_owner
*
);
extern
struct
nfs4_state
*
nfs4_get_open_state
(
struct
inode
*
,
struct
nfs4_state_owner
*
);
extern
void
nfs4_put_open_state
(
struct
nfs4_state
*
);
extern
void
nfs4_put_open_state
(
struct
nfs4_state
*
);
extern
void
nfs4_increment_seqid
(
int
status
,
struct
nfs4_state_owner
*
sp
);
extern
void
nfs4_increment_seqid
(
int
status
,
struct
nfs4_state_owner
*
sp
);
extern
void
nfs4_recover_state
(
struct
nfs4_client
*
);
extern
int
nfs4_handle_error
(
struct
nfs_server
*
,
int
);
extern
void
nfs4_schedule_state_recovery
(
struct
nfs4_client
*
);
struct
nfs4_mount_data
;
struct
nfs4_mount_data
;
#else
#else
...
...
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