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
nexedi
linux
Commits
8383e460
Commit
8383e460
authored
Jul 06, 2007
by
Trond Myklebust
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
NFSv4: Use RCU to protect delegations
Signed-off-by:
Trond Myklebust
<
Trond.Myklebust@netapp.com
>
parent
13437e12
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
73 additions
and
55 deletions
+73
-55
fs/nfs/delegation.c
fs/nfs/delegation.c
+63
-51
fs/nfs/delegation.h
fs/nfs/delegation.h
+10
-4
No files found.
fs/nfs/delegation.c
View file @
8383e460
...
...
@@ -27,6 +27,13 @@ static void nfs_free_delegation(struct nfs_delegation *delegation)
kfree
(
delegation
);
}
static
void
nfs_free_delegation_callback
(
struct
rcu_head
*
head
)
{
struct
nfs_delegation
*
delegation
=
container_of
(
head
,
struct
nfs_delegation
,
rcu
);
nfs_free_delegation
(
delegation
);
}
static
int
nfs_delegation_claim_locks
(
struct
nfs_open_context
*
ctx
,
struct
nfs4_state
*
state
)
{
struct
inode
*
inode
=
state
->
inode
;
...
...
@@ -133,10 +140,10 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct
delegation
->
inode
=
inode
;
spin_lock
(
&
clp
->
cl_lock
);
if
(
nfsi
->
delegation
==
NULL
)
{
list_add
(
&
delegation
->
super_list
,
&
clp
->
cl_delegations
);
nfsi
->
delegation
=
delegation
;
if
(
rcu_dereference
(
nfsi
->
delegation
)
==
NULL
)
{
list_add_rcu
(
&
delegation
->
super_list
,
&
clp
->
cl_delegations
);
nfsi
->
delegation_state
=
delegation
->
type
;
rcu_assign_pointer
(
nfsi
->
delegation
,
delegation
);
delegation
=
NULL
;
}
else
{
if
(
memcmp
(
&
delegation
->
stateid
,
&
nfsi
->
delegation
->
stateid
,
...
...
@@ -157,7 +164,7 @@ static int nfs_do_return_delegation(struct inode *inode, struct nfs_delegation *
int
res
=
0
;
res
=
nfs4_proc_delegreturn
(
inode
,
delegation
->
cred
,
&
delegation
->
stateid
);
nfs_free_delegation
(
delegation
);
call_rcu
(
&
delegation
->
rcu
,
nfs_free_delegation_callback
);
return
res
;
}
...
...
@@ -191,16 +198,16 @@ static int __nfs_inode_return_delegation(struct inode *inode, struct nfs_delegat
static
struct
nfs_delegation
*
nfs_detach_delegation_locked
(
struct
nfs_inode
*
nfsi
,
const
nfs4_stateid
*
stateid
)
{
struct
nfs_delegation
*
delegation
=
nfsi
->
delegation
;
struct
nfs_delegation
*
delegation
=
rcu_dereference
(
nfsi
->
delegation
)
;
if
(
delegation
==
NULL
)
goto
nomatch
;
if
(
stateid
!=
NULL
&&
memcmp
(
delegation
->
stateid
.
data
,
stateid
->
data
,
sizeof
(
delegation
->
stateid
.
data
))
!=
0
)
goto
nomatch
;
list_del_init
(
&
delegation
->
super_list
);
nfsi
->
delegation
=
NULL
;
list_del_rcu
(
&
delegation
->
super_list
);
nfsi
->
delegation_state
=
0
;
rcu_assign_pointer
(
nfsi
->
delegation
,
NULL
);
return
delegation
;
nomatch:
return
NULL
;
...
...
@@ -213,7 +220,7 @@ int nfs_inode_return_delegation(struct inode *inode)
struct
nfs_delegation
*
delegation
;
int
err
=
0
;
if
(
nfsi
->
delegation_state
!=
0
)
{
if
(
rcu_dereference
(
nfsi
->
delegation
)
!=
NULL
)
{
spin_lock
(
&
clp
->
cl_lock
);
delegation
=
nfs_detach_delegation_locked
(
nfsi
,
NULL
);
spin_unlock
(
&
clp
->
cl_lock
);
...
...
@@ -235,20 +242,23 @@ void nfs_return_all_delegations(struct super_block *sb)
if
(
clp
==
NULL
)
return
;
restart:
spin_lock
(
&
clp
->
cl_lock
);
list_for_each_entry
(
delegation
,
&
clp
->
cl_delegations
,
super_list
)
{
rcu_read_lock
(
);
list_for_each_entry
_rcu
(
delegation
,
&
clp
->
cl_delegations
,
super_list
)
{
if
(
delegation
->
inode
->
i_sb
!=
sb
)
continue
;
inode
=
igrab
(
delegation
->
inode
);
if
(
inode
==
NULL
)
continue
;
nfs_detach_delegation_locked
(
NFS_I
(
inode
),
NULL
);
spin_lock
(
&
clp
->
cl_lock
);
delegation
=
nfs_detach_delegation_locked
(
NFS_I
(
inode
),
NULL
);
spin_unlock
(
&
clp
->
cl_lock
);
__nfs_inode_return_delegation
(
inode
,
delegation
);
rcu_read_unlock
();
if
(
delegation
!=
NULL
)
__nfs_inode_return_delegation
(
inode
,
delegation
);
iput
(
inode
);
goto
restart
;
}
spin_unlock
(
&
clp
->
cl_lock
);
rcu_read_unlock
(
);
}
static
int
nfs_do_expire_all_delegations
(
void
*
ptr
)
...
...
@@ -259,23 +269,26 @@ static int nfs_do_expire_all_delegations(void *ptr)
allow_signal
(
SIGKILL
);
restart:
spin_lock
(
&
clp
->
cl_lock
);
if
(
test_bit
(
NFS4CLNT_STATE_RECOVER
,
&
clp
->
cl_state
)
!=
0
)
goto
out
;
if
(
test_bit
(
NFS4CLNT_LEASE_EXPIRED
,
&
clp
->
cl_state
)
==
0
)
goto
out
;
list_for_each_entry
(
delegation
,
&
clp
->
cl_delegations
,
super_list
)
{
rcu_read_lock
();
list_for_each_entry_rcu
(
delegation
,
&
clp
->
cl_delegations
,
super_list
)
{
inode
=
igrab
(
delegation
->
inode
);
if
(
inode
==
NULL
)
continue
;
nfs_detach_delegation_locked
(
NFS_I
(
inode
),
NULL
);
spin_lock
(
&
clp
->
cl_lock
);
delegation
=
nfs_detach_delegation_locked
(
NFS_I
(
inode
),
NULL
);
spin_unlock
(
&
clp
->
cl_lock
);
__nfs_inode_return_delegation
(
inode
,
delegation
);
rcu_read_unlock
();
if
(
delegation
)
__nfs_inode_return_delegation
(
inode
,
delegation
);
iput
(
inode
);
goto
restart
;
}
rcu_read_unlock
();
out:
spin_unlock
(
&
clp
->
cl_lock
);
nfs_put_client
(
clp
);
module_put_and_exit
(
0
);
}
...
...
@@ -306,18 +319,21 @@ void nfs_handle_cb_pathdown(struct nfs_client *clp)
if
(
clp
==
NULL
)
return
;
restart:
spin_lock
(
&
clp
->
cl_lock
);
list_for_each_entry
(
delegation
,
&
clp
->
cl_delegations
,
super_list
)
{
rcu_read_lock
(
);
list_for_each_entry
_rcu
(
delegation
,
&
clp
->
cl_delegations
,
super_list
)
{
inode
=
igrab
(
delegation
->
inode
);
if
(
inode
==
NULL
)
continue
;
nfs_detach_delegation_locked
(
NFS_I
(
inode
),
NULL
);
spin_lock
(
&
clp
->
cl_lock
);
delegation
=
nfs_detach_delegation_locked
(
NFS_I
(
inode
),
NULL
);
spin_unlock
(
&
clp
->
cl_lock
);
__nfs_inode_return_delegation
(
inode
,
delegation
);
rcu_read_unlock
();
if
(
delegation
!=
NULL
)
__nfs_inode_return_delegation
(
inode
,
delegation
);
iput
(
inode
);
goto
restart
;
}
spin_unlock
(
&
clp
->
cl_lock
);
rcu_read_unlock
(
);
}
struct
recall_threadargs
{
...
...
@@ -391,14 +407,14 @@ struct inode *nfs_delegation_find_inode(struct nfs_client *clp, const struct nfs
{
struct
nfs_delegation
*
delegation
;
struct
inode
*
res
=
NULL
;
spin_lock
(
&
clp
->
cl_lock
);
list_for_each_entry
(
delegation
,
&
clp
->
cl_delegations
,
super_list
)
{
rcu_read_lock
(
);
list_for_each_entry
_rcu
(
delegation
,
&
clp
->
cl_delegations
,
super_list
)
{
if
(
nfs_compare_fh
(
fhandle
,
&
NFS_I
(
delegation
->
inode
)
->
fh
)
==
0
)
{
res
=
igrab
(
delegation
->
inode
);
break
;
}
}
spin_unlock
(
&
clp
->
cl_lock
);
rcu_read_unlock
(
);
return
res
;
}
...
...
@@ -408,10 +424,10 @@ struct inode *nfs_delegation_find_inode(struct nfs_client *clp, const struct nfs
void
nfs_delegation_mark_reclaim
(
struct
nfs_client
*
clp
)
{
struct
nfs_delegation
*
delegation
;
spin_lock
(
&
clp
->
cl_lock
);
list_for_each_entry
(
delegation
,
&
clp
->
cl_delegations
,
super_list
)
rcu_read_lock
(
);
list_for_each_entry
_rcu
(
delegation
,
&
clp
->
cl_delegations
,
super_list
)
delegation
->
flags
|=
NFS_DELEGATION_NEED_RECLAIM
;
spin_unlock
(
&
clp
->
cl_lock
);
rcu_read_unlock
(
);
}
/*
...
...
@@ -419,39 +435,35 @@ void nfs_delegation_mark_reclaim(struct nfs_client *clp)
*/
void
nfs_delegation_reap_unclaimed
(
struct
nfs_client
*
clp
)
{
struct
nfs_delegation
*
delegation
,
*
n
;
LIST_HEAD
(
head
);
spin_lock
(
&
clp
->
cl_lock
);
list_for_each_entry_
safe
(
delegation
,
n
,
&
clp
->
cl_delegations
,
super_list
)
{
struct
nfs_delegation
*
delegation
;
restart:
rcu_read_lock
(
);
list_for_each_entry_
rcu
(
delegatio
n
,
&
clp
->
cl_delegations
,
super_list
)
{
if
((
delegation
->
flags
&
NFS_DELEGATION_NEED_RECLAIM
)
==
0
)
continue
;
list_move
(
&
delegation
->
super_list
,
&
head
);
NFS_I
(
delegation
->
inode
)
->
delegation
=
NULL
;
NFS_I
(
delegation
->
inode
)
->
delegation_state
=
0
;
}
spin_unlock
(
&
clp
->
cl_lock
);
while
(
!
list_empty
(
&
head
))
{
delegation
=
list_entry
(
head
.
next
,
struct
nfs_delegation
,
super_list
);
list_del
(
&
delegation
->
super_list
);
nfs_free_delegation
(
delegation
);
spin_lock
(
&
clp
->
cl_lock
);
delegation
=
nfs_detach_delegation_locked
(
NFS_I
(
delegation
->
inode
),
NULL
);
spin_unlock
(
&
clp
->
cl_lock
);
rcu_read_unlock
();
if
(
delegation
!=
NULL
)
call_rcu
(
&
delegation
->
rcu
,
nfs_free_delegation_callback
);
goto
restart
;
}
rcu_read_unlock
();
}
int
nfs4_copy_delegation_stateid
(
nfs4_stateid
*
dst
,
struct
inode
*
inode
)
{
struct
nfs_client
*
clp
=
NFS_SERVER
(
inode
)
->
nfs_client
;
struct
nfs_inode
*
nfsi
=
NFS_I
(
inode
);
struct
nfs_delegation
*
delegation
;
int
re
s
=
0
;
int
re
t
=
0
;
if
(
nfsi
->
delegation_state
==
0
)
return
0
;
spin_lock
(
&
clp
->
cl_lock
);
delegation
=
nfsi
->
delegation
;
rcu_read_lock
();
delegation
=
rcu_dereference
(
nfsi
->
delegation
);
if
(
delegation
!=
NULL
)
{
memcpy
(
dst
->
data
,
delegation
->
stateid
.
data
,
sizeof
(
dst
->
data
));
re
s
=
1
;
re
t
=
1
;
}
spin_unlock
(
&
clp
->
cl_lock
);
return
re
s
;
rcu_read_unlock
(
);
return
re
t
;
}
fs/nfs/delegation.h
View file @
8383e460
...
...
@@ -22,6 +22,7 @@ struct nfs_delegation {
long
flags
;
loff_t
maxsize
;
__u64
change_attr
;
struct
rcu_head
rcu
;
};
int
nfs_inode_set_delegation
(
struct
inode
*
inode
,
struct
rpc_cred
*
cred
,
struct
nfs_openres
*
res
);
...
...
@@ -45,11 +46,16 @@ int nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode);
static
inline
int
nfs_have_delegation
(
struct
inode
*
inode
,
int
flags
)
{
struct
nfs_delegation
*
delegation
;
int
ret
=
0
;
flags
&=
FMODE_READ
|
FMODE_WRITE
;
smp_rmb
();
if
((
NFS_I
(
inode
)
->
delegation_state
&
flags
)
==
flags
)
return
1
;
return
0
;
rcu_read_lock
();
delegation
=
rcu_dereference
(
NFS_I
(
inode
)
->
delegation
);
if
(
delegation
!=
NULL
&&
(
delegation
->
type
&
flags
)
==
flags
)
ret
=
1
;
rcu_read_unlock
();
return
ret
;
}
#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