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
477d40b4
Commit
477d40b4
authored
Aug 23, 2004
by
Trond Myklebust
Browse files
Options
Browse Files
Download
Plain Diff
Merge fys.uio.no:/home/linux/bitkeeper/nfsclient-2.6
into fys.uio.no:/home/linux/bitkeeper/work/nfsclient-2.6
parents
fec00732
60fa4cfb
Changes
15
Hide whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
1132 additions
and
732 deletions
+1132
-732
fs/nfs/dir.c
fs/nfs/dir.c
+7
-1
fs/nfs/direct.c
fs/nfs/direct.c
+27
-20
fs/nfs/file.c
fs/nfs/file.c
+6
-4
fs/nfs/inode.c
fs/nfs/inode.c
+103
-35
fs/nfs/nfs3proc.c
fs/nfs/nfs3proc.c
+10
-47
fs/nfs/nfs4proc.c
fs/nfs/nfs4proc.c
+604
-267
fs/nfs/nfs4state.c
fs/nfs/nfs4state.c
+148
-132
fs/nfs/nfs4xdr.c
fs/nfs/nfs4xdr.c
+39
-30
fs/nfs/pagelist.c
fs/nfs/pagelist.c
+28
-19
fs/nfs/proc.c
fs/nfs/proc.c
+8
-45
fs/nfs/read.c
fs/nfs/read.c
+38
-24
fs/nfs/write.c
fs/nfs/write.c
+50
-50
include/linux/nfs_fs.h
include/linux/nfs_fs.h
+45
-23
include/linux/nfs_page.h
include/linux/nfs_page.h
+7
-22
include/linux/nfs_xdr.h
include/linux/nfs_xdr.h
+12
-13
No files found.
fs/nfs/dir.c
View file @
477d40b4
...
...
@@ -982,12 +982,18 @@ static int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fhandle,
/* We may have been initialized further down */
if
(
dentry
->
d_inode
)
return
0
;
if
(
fhandle
->
size
==
0
||
!
(
fattr
->
valid
&
NFS_ATTR_FATTR
)
)
{
if
(
fhandle
->
size
==
0
)
{
struct
inode
*
dir
=
dentry
->
d_parent
->
d_inode
;
error
=
NFS_PROTO
(
dir
)
->
lookup
(
dir
,
&
dentry
->
d_name
,
fhandle
,
fattr
);
if
(
error
)
goto
out_err
;
}
if
(
!
(
fattr
->
valid
&
NFS_ATTR_FATTR
))
{
struct
nfs_server
*
server
=
NFS_SB
(
dentry
->
d_sb
);
error
=
server
->
rpc_ops
->
getattr
(
server
,
fhandle
,
fattr
);
if
(
error
<
0
)
goto
out_err
;
}
inode
=
nfs_fhget
(
dentry
->
d_sb
,
fhandle
,
fattr
);
if
(
inode
)
{
d_instantiate
(
dentry
,
inode
);
...
...
fs/nfs/direct.c
View file @
477d40b4
...
...
@@ -110,7 +110,7 @@ nfs_free_user_pages(struct page **pages, int npages, int do_dirty)
* nfs_direct_read_seg - Read in one iov segment. Generate separate
* read RPCs for each "rsize" bytes.
* @inode: target inode
* @
file: target file (may be NULL)
* @
ctx: target file open context
* user_addr: starting address of this segment of user's buffer
* count: size of this segment
* file_offset: offset in file to begin the operation
...
...
@@ -118,7 +118,7 @@ nfs_free_user_pages(struct page **pages, int npages, int do_dirty)
* nr_pages: size of pages array
*/
static
int
nfs_direct_read_seg
(
struct
inode
*
inode
,
struct
file
*
file
,
nfs_direct_read_seg
(
struct
inode
*
inode
,
struct
nfs_open_context
*
ctx
,
unsigned
long
user_addr
,
size_t
count
,
loff_t
file_offset
,
struct
page
**
pages
,
int
nr_pages
)
{
...
...
@@ -127,9 +127,10 @@ nfs_direct_read_seg(struct inode *inode, struct file *file,
int
curpage
=
0
;
struct
nfs_read_data
rdata
=
{
.
inode
=
inode
,
.
cred
=
ctx
->
cred
,
.
args
=
{
.
fh
=
NFS_FH
(
inode
),
.
lockowner
=
current
->
files
,
.
context
=
ctx
,
},
.
res
=
{
.
fattr
=
&
rdata
.
fattr
,
...
...
@@ -151,7 +152,7 @@ nfs_direct_read_seg(struct inode *inode, struct file *file,
user_addr
+
tot_bytes
,
rdata
.
args
.
pgbase
,
curpage
);
lock_kernel
();
result
=
NFS_PROTO
(
inode
)
->
read
(
&
rdata
,
file
);
result
=
NFS_PROTO
(
inode
)
->
read
(
&
rdata
);
unlock_kernel
();
if
(
result
<=
0
)
{
...
...
@@ -183,7 +184,7 @@ nfs_direct_read_seg(struct inode *inode, struct file *file,
* nfs_direct_read - For each iov segment, map the user's buffer
* then generate read RPCs.
* @inode: target inode
* @
file: target file (may be NULL)
* @
ctx: target file open context
* @iov: array of vectors that define I/O buffer
* file_offset: offset in file to begin the operation
* nr_segs: size of iovec array
...
...
@@ -193,7 +194,7 @@ nfs_direct_read_seg(struct inode *inode, struct file *file,
* server.
*/
static
ssize_t
nfs_direct_read
(
struct
inode
*
inode
,
struct
file
*
file
,
nfs_direct_read
(
struct
inode
*
inode
,
struct
nfs_open_context
*
ctx
,
const
struct
iovec
*
iov
,
loff_t
file_offset
,
unsigned
long
nr_segs
)
{
...
...
@@ -216,7 +217,7 @@ nfs_direct_read(struct inode *inode, struct file *file,
return
page_count
;
}
result
=
nfs_direct_read_seg
(
inode
,
file
,
user_addr
,
size
,
result
=
nfs_direct_read_seg
(
inode
,
ctx
,
user_addr
,
size
,
file_offset
,
pages
,
page_count
);
nfs_free_user_pages
(
pages
,
page_count
,
1
);
...
...
@@ -239,7 +240,7 @@ nfs_direct_read(struct inode *inode, struct file *file,
* nfs_direct_write_seg - Write out one iov segment. Generate separate
* write RPCs for each "wsize" bytes, then commit.
* @inode: target inode
* @
file: target file (may be NULL)
* @
ctx: target file open context
* user_addr: starting address of this segment of user's buffer
* count: size of this segment
* file_offset: offset in file to begin the operation
...
...
@@ -247,7 +248,7 @@ nfs_direct_read(struct inode *inode, struct file *file,
* nr_pages: size of pages array
*/
static
int
nfs_direct_write_seg
(
struct
inode
*
inode
,
struct
file
*
file
,
nfs_direct_write_seg
(
struct
inode
*
inode
,
struct
nfs_open_context
*
ctx
,
unsigned
long
user_addr
,
size_t
count
,
loff_t
file_offset
,
struct
page
**
pages
,
int
nr_pages
)
{
...
...
@@ -257,9 +258,10 @@ nfs_direct_write_seg(struct inode *inode, struct file *file,
struct
nfs_writeverf
first_verf
;
struct
nfs_write_data
wdata
=
{
.
inode
=
inode
,
.
cred
=
ctx
->
cred
,
.
args
=
{
.
fh
=
NFS_FH
(
inode
),
.
lockowner
=
current
->
files
,
.
context
=
ctx
,
},
.
res
=
{
.
fattr
=
&
wdata
.
fattr
,
...
...
@@ -290,7 +292,7 @@ nfs_direct_write_seg(struct inode *inode, struct file *file,
user_addr
+
tot_bytes
,
wdata
.
args
.
pgbase
,
curpage
);
lock_kernel
();
result
=
NFS_PROTO
(
inode
)
->
write
(
&
wdata
,
file
);
result
=
NFS_PROTO
(
inode
)
->
write
(
&
wdata
);
unlock_kernel
();
if
(
result
<=
0
)
{
...
...
@@ -325,7 +327,7 @@ nfs_direct_write_seg(struct inode *inode, struct file *file,
wdata
.
args
.
offset
=
file_offset
;
lock_kernel
();
result
=
NFS_PROTO
(
inode
)
->
commit
(
&
wdata
,
file
);
result
=
NFS_PROTO
(
inode
)
->
commit
(
&
wdata
);
unlock_kernel
();
if
(
result
<
0
||
memcmp
(
&
first_verf
.
verifier
,
...
...
@@ -349,7 +351,7 @@ nfs_direct_write_seg(struct inode *inode, struct file *file,
* nfs_direct_write - For each iov segment, map the user's buffer
* then generate write and commit RPCs.
* @inode: target inode
* @
file: target file (may be NULL)
* @
ctx: target file open context
* @iov: array of vectors that define I/O buffer
* file_offset: offset in file to begin the operation
* nr_segs: size of iovec array
...
...
@@ -358,8 +360,7 @@ nfs_direct_write_seg(struct inode *inode, struct file *file,
* that non-direct readers might access, so they will pick up these
* writes immediately.
*/
static
ssize_t
nfs_direct_write
(
struct
inode
*
inode
,
struct
file
*
file
,
static
int
nfs_direct_write
(
struct
inode
*
inode
,
struct
nfs_open_context
*
ctx
,
const
struct
iovec
*
iov
,
loff_t
file_offset
,
unsigned
long
nr_segs
)
{
...
...
@@ -382,7 +383,7 @@ nfs_direct_write(struct inode *inode, struct file *file,
return
page_count
;
}
result
=
nfs_direct_write_seg
(
inode
,
file
,
user_addr
,
size
,
result
=
nfs_direct_write_seg
(
inode
,
ctx
,
user_addr
,
size
,
file_offset
,
pages
,
page_count
);
nfs_free_user_pages
(
pages
,
page_count
,
0
);
...
...
@@ -414,6 +415,7 @@ nfs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
{
ssize_t
result
=
-
EINVAL
;
struct
file
*
file
=
iocb
->
ki_filp
;
struct
nfs_open_context
*
ctx
;
struct
dentry
*
dentry
=
file
->
f_dentry
;
struct
inode
*
inode
=
dentry
->
d_inode
;
...
...
@@ -423,19 +425,20 @@ nfs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
if
(
!
is_sync_kiocb
(
iocb
))
return
result
;
ctx
=
(
struct
nfs_open_context
*
)
file
->
private_data
;
switch
(
rw
)
{
case
READ
:
dprintk
(
"NFS: direct_IO(read) (%s) off/no(%Lu/%lu)
\n
"
,
dentry
->
d_name
.
name
,
file_offset
,
nr_segs
);
result
=
nfs_direct_read
(
inode
,
file
,
iov
,
result
=
nfs_direct_read
(
inode
,
ctx
,
iov
,
file_offset
,
nr_segs
);
break
;
case
WRITE
:
dprintk
(
"NFS: direct_IO(write) (%s) off/no(%Lu/%lu)
\n
"
,
dentry
->
d_name
.
name
,
file_offset
,
nr_segs
);
result
=
nfs_direct_write
(
inode
,
file
,
iov
,
result
=
nfs_direct_write
(
inode
,
ctx
,
iov
,
file_offset
,
nr_segs
);
break
;
default:
...
...
@@ -471,6 +474,8 @@ nfs_file_direct_read(struct kiocb *iocb, char __user *buf, size_t count, loff_t
ssize_t
retval
=
-
EINVAL
;
loff_t
*
ppos
=
&
iocb
->
ki_pos
;
struct
file
*
file
=
iocb
->
ki_filp
;
struct
nfs_open_context
*
ctx
=
(
struct
nfs_open_context
*
)
file
->
private_data
;
struct
dentry
*
dentry
=
file
->
f_dentry
;
struct
address_space
*
mapping
=
file
->
f_mapping
;
struct
inode
*
inode
=
mapping
->
host
;
...
...
@@ -502,7 +507,7 @@ nfs_file_direct_read(struct kiocb *iocb, char __user *buf, size_t count, loff_t
goto
out
;
}
retval
=
nfs_direct_read
(
inode
,
file
,
&
iov
,
pos
,
1
);
retval
=
nfs_direct_read
(
inode
,
ctx
,
&
iov
,
pos
,
1
);
if
(
retval
>
0
)
*
ppos
=
pos
+
retval
;
...
...
@@ -542,6 +547,8 @@ nfs_file_direct_write(struct kiocb *iocb, const char __user *buf, size_t count,
loff_t
*
ppos
=
&
iocb
->
ki_pos
;
unsigned
long
limit
=
current
->
rlim
[
RLIMIT_FSIZE
].
rlim_cur
;
struct
file
*
file
=
iocb
->
ki_filp
;
struct
nfs_open_context
*
ctx
=
(
struct
nfs_open_context
*
)
file
->
private_data
;
struct
dentry
*
dentry
=
file
->
f_dentry
;
struct
address_space
*
mapping
=
file
->
f_mapping
;
struct
inode
*
inode
=
mapping
->
host
;
...
...
@@ -589,7 +596,7 @@ nfs_file_direct_write(struct kiocb *iocb, const char __user *buf, size_t count,
goto
out
;
}
retval
=
nfs_direct_write
(
inode
,
file
,
&
iov
,
pos
,
1
);
retval
=
nfs_direct_write
(
inode
,
ctx
,
&
iov
,
pos
,
1
);
if
(
mapping
->
nrpages
)
invalidate_inode_pages2
(
mapping
);
if
(
retval
>
0
)
...
...
fs/nfs/file.c
View file @
477d40b4
...
...
@@ -113,6 +113,7 @@ nfs_file_release(struct inode *inode, struct file *filp)
static
int
nfs_file_flush
(
struct
file
*
file
)
{
struct
nfs_open_context
*
ctx
=
(
struct
nfs_open_context
*
)
file
->
private_data
;
struct
inode
*
inode
=
file
->
f_dentry
->
d_inode
;
int
status
;
...
...
@@ -124,8 +125,8 @@ nfs_file_flush(struct file *file)
/* Ensure that data+attribute caches are up to date after close() */
status
=
nfs_wb_all
(
inode
);
if
(
!
status
)
{
status
=
file
->
f_
error
;
file
->
f_
error
=
0
;
status
=
ctx
->
error
;
ctx
->
error
=
0
;
if
(
!
status
)
__nfs_revalidate_inode
(
NFS_SERVER
(
inode
),
inode
);
}
...
...
@@ -197,6 +198,7 @@ nfs_file_mmap(struct file * file, struct vm_area_struct * vma)
static
int
nfs_fsync
(
struct
file
*
file
,
struct
dentry
*
dentry
,
int
datasync
)
{
struct
nfs_open_context
*
ctx
=
(
struct
nfs_open_context
*
)
file
->
private_data
;
struct
inode
*
inode
=
dentry
->
d_inode
;
int
status
;
...
...
@@ -205,8 +207,8 @@ nfs_fsync(struct file *file, struct dentry *dentry, int datasync)
lock_kernel
();
status
=
nfs_wb_all
(
inode
);
if
(
!
status
)
{
status
=
file
->
f_
error
;
file
->
f_
error
=
0
;
status
=
ctx
->
error
;
ctx
->
error
=
0
;
}
unlock_kernel
();
return
status
;
...
...
fs/nfs/inode.c
View file @
477d40b4
...
...
@@ -121,8 +121,9 @@ nfs_delete_inode(struct inode * inode)
{
dprintk
(
"NFS: delete_inode(%s/%ld)
\n
"
,
inode
->
i_sb
->
s_id
,
inode
->
i_ino
);
nfs_wb_all
(
inode
);
/*
* The following
can never actually
happen...
* The following
should never
happen...
*/
if
(
nfs_have_writebacks
(
inode
))
{
printk
(
KERN_ERR
"nfs_delete_inode: inode %ld has pending RPC requests
\n
"
,
inode
->
i_ino
);
...
...
@@ -139,10 +140,10 @@ static void
nfs_clear_inode
(
struct
inode
*
inode
)
{
struct
nfs_inode
*
nfsi
=
NFS_I
(
inode
);
struct
rpc_cred
*
cred
=
nfsi
->
mm_cred
;
struct
rpc_cred
*
cred
;
if
(
cred
)
put_rpccred
(
cred
);
nfs_wb_all
(
inode
);
BUG_ON
(
!
list_empty
(
&
nfsi
->
open_files
)
);
cred
=
nfsi
->
cache_access
.
cred
;
if
(
cred
)
put_rpccred
(
cred
);
...
...
@@ -812,53 +813,114 @@ int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
return
err
;
}
struct
nfs_open_context
*
alloc_nfs_open_context
(
struct
dentry
*
dentry
,
struct
rpc_cred
*
cred
)
{
struct
nfs_open_context
*
ctx
;
ctx
=
(
struct
nfs_open_context
*
)
kmalloc
(
sizeof
(
*
ctx
),
GFP_KERNEL
);
if
(
ctx
!=
NULL
)
{
atomic_set
(
&
ctx
->
count
,
1
);
ctx
->
dentry
=
dget
(
dentry
);
ctx
->
cred
=
get_rpccred
(
cred
);
ctx
->
state
=
NULL
;
ctx
->
lockowner
=
current
->
files
;
ctx
->
error
=
0
;
init_waitqueue_head
(
&
ctx
->
waitq
);
}
return
ctx
;
}
struct
nfs_open_context
*
get_nfs_open_context
(
struct
nfs_open_context
*
ctx
)
{
if
(
ctx
!=
NULL
)
atomic_inc
(
&
ctx
->
count
);
return
ctx
;
}
void
put_nfs_open_context
(
struct
nfs_open_context
*
ctx
)
{
if
(
atomic_dec_and_test
(
&
ctx
->
count
))
{
if
(
ctx
->
state
!=
NULL
)
nfs4_close_state
(
ctx
->
state
,
ctx
->
mode
);
if
(
ctx
->
cred
!=
NULL
)
put_rpccred
(
ctx
->
cred
);
dput
(
ctx
->
dentry
);
kfree
(
ctx
);
}
}
/*
* Ensure that mmap has a recent RPC credential for use when writing out
* shared pages
*/
void
nfs_set_mmcred
(
struct
inode
*
inode
,
struct
rpc_cred
*
cred
)
void
nfs_file_set_open_context
(
struct
file
*
filp
,
struct
nfs_open_context
*
ctx
)
{
struct
rpc_cred
**
p
=
&
NFS_I
(
inode
)
->
mm_cred
,
*
oldcred
=
*
p
;
struct
inode
*
inode
=
filp
->
f_dentry
->
d_inode
;
struct
nfs_inode
*
nfsi
=
NFS_I
(
inode
)
;
*
p
=
get_rpccred
(
cred
);
if
(
oldcred
)
put_rpccred
(
oldcred
);
filp
->
private_data
=
get_nfs_open_context
(
ctx
);
spin_lock
(
&
inode
->
i_lock
);
list_add
(
&
ctx
->
list
,
&
nfsi
->
open_files
);
spin_unlock
(
&
inode
->
i_lock
);
}
struct
nfs_open_context
*
nfs_find_open_context
(
struct
inode
*
inode
,
int
mode
)
{
struct
nfs_inode
*
nfsi
=
NFS_I
(
inode
);
struct
nfs_open_context
*
pos
,
*
ctx
=
NULL
;
spin_lock
(
&
inode
->
i_lock
);
list_for_each_entry
(
pos
,
&
nfsi
->
open_files
,
list
)
{
if
((
pos
->
mode
&
mode
)
==
mode
)
{
ctx
=
get_nfs_open_context
(
pos
);
break
;
}
}
spin_unlock
(
&
inode
->
i_lock
);
return
ctx
;
}
void
nfs_file_clear_open_context
(
struct
file
*
filp
)
{
struct
inode
*
inode
=
filp
->
f_dentry
->
d_inode
;
struct
nfs_open_context
*
ctx
=
(
struct
nfs_open_context
*
)
filp
->
private_data
;
if
(
ctx
)
{
filp
->
private_data
=
NULL
;
spin_lock
(
&
inode
->
i_lock
);
list_del
(
&
ctx
->
list
);
spin_unlock
(
&
inode
->
i_lock
);
put_nfs_open_context
(
ctx
);
}
}
/*
* These are probably going to contain hooks for
* allocating and releasing RPC credentials for
* the file. I'll have to think about Tronds patch
* a bit more..
* These allocate and release file read/write context information.
*/
int
nfs_open
(
struct
inode
*
inode
,
struct
file
*
filp
)
{
struct
rpc_auth
*
auth
;
struct
nfs_open_context
*
ctx
;
struct
rpc_cred
*
cred
;
auth
=
NFS_CLIENT
(
inode
)
->
cl_auth
;
cred
=
rpcauth_lookupcred
(
auth
,
0
);
filp
->
private_data
=
cred
;
if
((
filp
->
f_mode
&
FMODE_WRITE
)
!=
0
)
{
nfs_set_mmcred
(
inode
,
cred
);
if
((
cred
=
rpcauth_lookupcred
(
NFS_CLIENT
(
inode
)
->
cl_auth
,
0
))
==
NULL
)
return
-
ENOMEM
;
ctx
=
alloc_nfs_open_context
(
filp
->
f_dentry
,
cred
);
put_rpccred
(
cred
);
if
(
ctx
==
NULL
)
return
-
ENOMEM
;
ctx
->
mode
=
filp
->
f_mode
;
nfs_file_set_open_context
(
filp
,
ctx
);
put_nfs_open_context
(
ctx
);
if
((
filp
->
f_mode
&
FMODE_WRITE
)
!=
0
)
nfs_begin_data_update
(
inode
);
}
return
0
;
}
int
nfs_release
(
struct
inode
*
inode
,
struct
file
*
filp
)
{
struct
rpc_cred
*
cred
;
lock_kernel
();
if
((
filp
->
f_mode
&
FMODE_WRITE
)
!=
0
)
nfs_end_data_update
(
inode
);
cred
=
nfs_file_cred
(
filp
);
if
(
cred
)
put_rpccred
(
cred
);
unlock_kernel
();
nfs_file_clear_open_context
(
filp
);
return
0
;
}
...
...
@@ -899,7 +961,7 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
/* Protect against RPC races by saving the change attribute */
verifier
=
nfs_save_change_attribute
(
inode
);
status
=
NFS_PROTO
(
inode
)
->
getattr
(
inode
,
&
fattr
);
status
=
NFS_PROTO
(
inode
)
->
getattr
(
server
,
NFS_FH
(
inode
)
,
&
fattr
);
if
(
status
)
{
dfprintk
(
PAGECACHE
,
"nfs_revalidate_inode: (%s/%Ld) getattr failed, error=%d
\n
"
,
inode
->
i_sb
->
s_id
,
...
...
@@ -1397,6 +1459,9 @@ static void nfs4_clear_inode(struct inode *inode)
{
struct
nfs_inode
*
nfsi
=
NFS_I
(
inode
);
/* First call standard NFS clear_inode() code */
nfs_clear_inode
(
inode
);
/* Now clear out any remaining state */
while
(
!
list_empty
(
&
nfsi
->
open_states
))
{
struct
nfs4_state
*
state
;
...
...
@@ -1411,8 +1476,6 @@ static void nfs4_clear_inode(struct inode *inode)
BUG_ON
(
atomic_read
(
&
state
->
count
)
!=
1
);
nfs4_close_state
(
state
,
state
->
state
);
}
/* Now call standard NFS clear_inode() code */
nfs_clear_inode
(
inode
);
}
...
...
@@ -1510,8 +1573,13 @@ static int nfs4_fill_super(struct super_block *sb, struct nfs4_mount_data *data,
memcpy
(
clp
->
cl_ipaddr
,
server
->
ip_addr
,
sizeof
(
clp
->
cl_ipaddr
));
nfs_idmap_new
(
clp
);
}
if
(
list_empty
(
&
clp
->
cl_superblocks
))
clear_bit
(
NFS4CLNT_OK
,
&
clp
->
cl_state
);
if
(
list_empty
(
&
clp
->
cl_superblocks
))
{
err
=
nfs4_init_client
(
clp
);
if
(
err
!=
0
)
{
up_write
(
&
clp
->
cl_sem
);
goto
out_fail
;
}
}
list_add_tail
(
&
server
->
nfs4_siblings
,
&
clp
->
cl_superblocks
);
clnt
=
rpc_clone_client
(
clp
->
cl_rpcclient
);
if
(
!
IS_ERR
(
clnt
))
...
...
@@ -1712,7 +1780,6 @@ static struct inode *nfs_alloc_inode(struct super_block *sb)
if
(
!
nfsi
)
return
NULL
;
nfsi
->
flags
=
0
;
nfsi
->
mm_cred
=
NULL
;
nfs4_zero_state
(
nfsi
);
return
&
nfsi
->
vfs_inode
;
}
...
...
@@ -1732,6 +1799,7 @@ static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
spin_lock_init
(
&
nfsi
->
req_lock
);
INIT_LIST_HEAD
(
&
nfsi
->
dirty
);
INIT_LIST_HEAD
(
&
nfsi
->
commit
);
INIT_LIST_HEAD
(
&
nfsi
->
open_files
);
INIT_RADIX_TREE
(
&
nfsi
->
nfs_page_tree
,
GFP_ATOMIC
);
atomic_set
(
&
nfsi
->
data_updates
,
0
);
nfsi
->
ndirty
=
0
;
...
...
fs/nfs/nfs3proc.c
View file @
477d40b4
...
...
@@ -68,18 +68,6 @@ nfs3_async_handle_jukebox(struct rpc_task *task)
return
1
;
}
static
struct
rpc_cred
*
nfs_cred
(
struct
inode
*
inode
,
struct
file
*
filp
)
{
struct
rpc_cred
*
cred
=
NULL
;
if
(
filp
)
cred
=
(
struct
rpc_cred
*
)
filp
->
private_data
;
if
(
!
cred
)
cred
=
NFS_I
(
inode
)
->
mm_cred
;
return
cred
;
}
/*
* Bare-bones access to getattr: this is for nfs_read_super.
*/
...
...
@@ -104,14 +92,15 @@ nfs3_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
* One function for each procedure in the NFS protocol.
*/
static
int
nfs3_proc_getattr
(
struct
inode
*
inode
,
struct
nfs_fattr
*
fattr
)
nfs3_proc_getattr
(
struct
nfs_server
*
server
,
struct
nfs_fh
*
fhandle
,
struct
nfs_fattr
*
fattr
)
{
int
status
;
dprintk
(
"NFS call getattr
\n
"
);
fattr
->
valid
=
0
;
status
=
rpc_call
(
NFS_CLIENT
(
inode
)
,
NFS3PROC_GETATTR
,
NFS_FH
(
inode
)
,
fattr
,
0
);
status
=
rpc_call
(
server
->
client
,
NFS3PROC_GETATTR
,
fhandle
,
fattr
,
0
);
dprintk
(
"NFS reply getattr
\n
"
);
return
status
;
}
...
...
@@ -233,8 +222,7 @@ nfs3_proc_readlink(struct inode *inode, struct page *page)
return
status
;
}
static
int
nfs3_proc_read
(
struct
nfs_read_data
*
rdata
,
struct
file
*
filp
)
static
int
nfs3_proc_read
(
struct
nfs_read_data
*
rdata
)
{
int
flags
=
rdata
->
flags
;
struct
inode
*
inode
=
rdata
->
inode
;
...
...
@@ -243,13 +231,13 @@ nfs3_proc_read(struct nfs_read_data *rdata, struct file *filp)
.
rpc_proc
=
&
nfs3_procedures
[
NFS3PROC_READ
],
.
rpc_argp
=
&
rdata
->
args
,
.
rpc_resp
=
&
rdata
->
res
,
.
rpc_cred
=
rdata
->
cred
,
};
int
status
;
dprintk
(
"NFS call read %d @ %Ld
\n
"
,
rdata
->
args
.
count
,
(
long
long
)
rdata
->
args
.
offset
);
fattr
->
valid
=
0
;
msg
.
rpc_cred
=
nfs_cred
(
inode
,
filp
);
status
=
rpc_call_sync
(
NFS_CLIENT
(
inode
),
&
msg
,
flags
);
if
(
status
>=
0
)
nfs_refresh_inode
(
inode
,
fattr
);
...
...
@@ -257,8 +245,7 @@ nfs3_proc_read(struct nfs_read_data *rdata, struct file *filp)
return
status
;
}
static
int
nfs3_proc_write
(
struct
nfs_write_data
*
wdata
,
struct
file
*
filp
)
static
int
nfs3_proc_write
(
struct
nfs_write_data
*
wdata
)
{
int
rpcflags
=
wdata
->
flags
;
struct
inode
*
inode
=
wdata
->
inode
;
...
...
@@ -267,13 +254,13 @@ nfs3_proc_write(struct nfs_write_data *wdata, struct file *filp)
.
rpc_proc
=
&
nfs3_procedures
[
NFS3PROC_WRITE
],
.
rpc_argp
=
&
wdata
->
args
,
.
rpc_resp
=
&
wdata
->
res
,
.
rpc_cred
=
wdata
->
cred
,
};
int
status
;
dprintk
(
"NFS call write %d @ %Ld
\n
"
,
wdata
->
args
.
count
,
(
long
long
)
wdata
->
args
.
offset
);
fattr
->
valid
=
0
;
msg
.
rpc_cred
=
nfs_cred
(
inode
,
filp
);
status
=
rpc_call_sync
(
NFS_CLIENT
(
inode
),
&
msg
,
rpcflags
);
if
(
status
>=
0
)
nfs_refresh_inode
(
inode
,
fattr
);
...
...
@@ -281,8 +268,7 @@ nfs3_proc_write(struct nfs_write_data *wdata, struct file *filp)
return
status
<
0
?
status
:
wdata
->
res
.
count
;
}
static
int
nfs3_proc_commit
(
struct
nfs_write_data
*
cdata
,
struct
file
*
filp
)
static
int
nfs3_proc_commit
(
struct
nfs_write_data
*
cdata
)
{
struct
inode
*
inode
=
cdata
->
inode
;
struct
nfs_fattr
*
fattr
=
cdata
->
res
.
fattr
;
...
...
@@ -290,13 +276,13 @@ nfs3_proc_commit(struct nfs_write_data *cdata, struct file *filp)
.
rpc_proc
=
&
nfs3_procedures
[
NFS3PROC_COMMIT
],
.
rpc_argp
=
&
cdata
->
args
,
.
rpc_resp
=
&
cdata
->
res
,
.
rpc_cred
=
cdata
->
cred
,
};
int
status
;
dprintk
(
"NFS call commit %d @ %Ld
\n
"
,
cdata
->
args
.
count
,
(
long
long
)
cdata
->
args
.
offset
);
fattr
->
valid
=
0
;
msg
.
rpc_cred
=
nfs_cred
(
inode
,
filp
);
status
=
rpc_call_sync
(
NFS_CLIENT
(
inode
),
&
msg
,
0
);
if
(
status
>=
0
)
nfs_refresh_inode
(
inode
,
fattr
);
...
...
@@ -840,27 +826,6 @@ nfs3_proc_commit_setup(struct nfs_write_data *data, int how)
rpc_call_setup
(
task
,
&
msg
,
0
);
}
/*
* Set up the nfspage struct with the right credentials
*/
void
nfs3_request_init
(
struct
nfs_page
*
req
,
struct
file
*
filp
)
{
req
->
wb_cred
=
get_rpccred
(
nfs_cred
(
req
->
wb_inode
,
filp
));
}
static
int
nfs3_request_compatible
(
struct
nfs_page
*
req
,
struct
file
*
filp
,
struct
page
*
page
)
{
if
(
req
->
wb_file
!=
filp
)
return
0
;
if
(
req
->
wb_page
!=
page
)
return
0
;
if
(
req
->
wb_cred
!=
nfs_file_cred
(
filp
))
return
0
;
return
1
;
}
static
int
nfs3_proc_lock
(
struct
file
*
filp
,
int
cmd
,
struct
file_lock
*
fl
)
{
...
...
@@ -900,7 +865,5 @@ struct nfs_rpc_ops nfs_v3_clientops = {
.
commit_setup
=
nfs3_proc_commit_setup
,
.
file_open
=
nfs_open
,
.
file_release
=
nfs_release
,
.
request_init
=
nfs3_request_init
,
.
request_compatible
=
nfs3_request_compatible
,
.
lock
=
nfs3_proc_lock
,
};
fs/nfs/nfs4proc.c
View file @
477d40b4
...
...
@@ -49,7 +49,8 @@
#define NFSDBG_FACILITY NFSDBG_PROC
#define NFS4_POLL_RETRY_TIME (15*HZ)
#define NFS4_POLL_RETRY_MIN (1*HZ)
#define NFS4_POLL_RETRY_MAX (15*HZ)
static
int
nfs4_do_fsinfo
(
struct
nfs_server
*
,
struct
nfs_fh
*
,
struct
nfs_fsinfo
*
);
static
int
nfs4_async_handle_error
(
struct
rpc_task
*
,
struct
nfs_server
*
);
...
...
@@ -189,8 +190,7 @@ static void update_changeattr(struct inode *inode, struct nfs4_change_info *cinf
* reclaim state on the server after a reboot.
* Assumes caller is holding the sp->so_sem
*/
int
nfs4_open_reclaim
(
struct
nfs4_state_owner
*
sp
,
struct
nfs4_state
*
state
)
static
int
_nfs4_open_reclaim
(
struct
nfs4_state_owner
*
sp
,
struct
nfs4_state
*
state
)
{
struct
inode
*
inode
=
state
->
inode
;
struct
nfs_server
*
server
=
NFS_SERVER
(
inode
);
...
...
@@ -227,15 +227,34 @@ nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *state)
return
status
;
}
int
nfs4_open_reclaim
(
struct
nfs4_state_owner
*
sp
,
struct
nfs4_state
*
state
)
{
struct
nfs_server
*
server
=
NFS_SERVER
(
state
->
inode
);
struct
nfs4_exception
exception
=
{
};
int
err
;
do
{
err
=
_nfs4_open_reclaim
(
sp
,
state
);
switch
(
err
)
{
case
0
:
case
-
NFS4ERR_STALE_CLIENTID
:
case
-
NFS4ERR_STALE_STATEID
:
case
-
NFS4ERR_EXPIRED
:
return
err
;
}
err
=
nfs4_handle_exception
(
server
,
err
,
&
exception
);
}
while
(
exception
.
retry
);
return
err
;
}
/*
* Returns an nfs4_state + an referenced inode
*/
struct
nfs4_state
*
nfs4_do_open
(
struct
inode
*
dir
,
struct
qstr
*
name
,
int
flags
,
struct
iattr
*
sattr
,
struct
rpc_cred
*
cred
)
static
int
_nfs4_do_open
(
struct
inode
*
dir
,
struct
qstr
*
name
,
int
flags
,
struct
iattr
*
sattr
,
struct
rpc_cred
*
cred
,
struct
nfs4_state
**
res
)
{
struct
nfs4_state_owner
*
sp
;
struct
nfs4_state
*
state
=
NULL
;
struct
nfs_server
*
server
=
NFS_SERVER
(
dir
);
struct
nfs4_client
*
clp
=
server
->
nfs4_state
;
struct
inode
*
inode
=
NULL
;
int
status
;
struct
nfs_fattr
f_attr
=
{
...
...
@@ -261,11 +280,12 @@ nfs4_do_open(struct inode *dir, struct qstr *name, int flags, struct iattr *satt
.
rpc_cred
=
cred
,
};
retry:
/* Protect against reboot recovery conflicts */
down_read
(
&
clp
->
cl_sem
);
status
=
-
ENOMEM
;
if
(
!
(
sp
=
nfs4_get_state_owner
(
NFS_SERVER
(
dir
)
,
cred
)))
{
if
(
!
(
sp
=
nfs4_get_state_owner
(
server
,
cred
)))
{
dprintk
(
"nfs4_do_open: nfs4_get_state_owner failed!
\n
"
);
goto
out
;
goto
out
_err
;
}
if
(
o_arg
.
createmode
&
NFS4_CREATE_EXCLUSIVE
){
u32
*
p
=
(
u32
*
)
o_arg
.
u
.
verifier
.
data
;
...
...
@@ -283,16 +303,21 @@ nfs4_do_open(struct inode *dir, struct qstr *name, int flags, struct iattr *satt
status
=
rpc_call_sync
(
server
->
client
,
&
msg
,
0
);
nfs4_increment_seqid
(
status
,
sp
);
if
(
status
)
goto
out_
up
;
goto
out_
err
;
update_changeattr
(
dir
,
&
o_res
.
cinfo
);
if
(
!
(
f_attr
.
valid
&
NFS_ATTR_FATTR
))
{
status
=
server
->
rpc_ops
->
getattr
(
server
,
&
o_res
.
fh
,
&
f_attr
);
if
(
status
<
0
)
goto
out_err
;
}
status
=
-
ENOMEM
;
inode
=
nfs_fhget
(
dir
->
i_sb
,
&
o_res
.
fh
,
&
f_attr
);
if
(
!
inode
)
goto
out_
up
;
goto
out_
err
;
state
=
nfs4_get_open_state
(
inode
,
sp
);
if
(
!
state
)
goto
out_
up
;
goto
out_
err
;
if
(
o_res
.
rflags
&
NFS4_OPEN_RESULT_CONFIRM
)
{
struct
nfs_open_confirmargs
oc_arg
=
{
...
...
@@ -311,7 +336,7 @@ nfs4_do_open(struct inode *dir, struct qstr *name, int flags, struct iattr *satt
status
=
rpc_call_sync
(
server
->
client
,
&
msg
,
0
);
nfs4_increment_seqid
(
status
,
sp
);
if
(
status
)
goto
out_
up
;
goto
out_
err
;
memcpy
(
&
state
->
stateid
,
&
oc_res
.
stateid
,
sizeof
(
state
->
stateid
));
}
else
memcpy
(
&
state
->
stateid
,
&
o_res
.
stateid
,
sizeof
(
state
->
stateid
));
...
...
@@ -325,44 +350,58 @@ nfs4_do_open(struct inode *dir, struct qstr *name, int flags, struct iattr *satt
up
(
&
sp
->
so_sema
);
nfs4_put_state_owner
(
sp
);
return
state
;
out_up:
up
(
&
sp
->
so_sema
);
nfs4_put_state_owner
(
sp
);
if
(
state
)
{
nfs4_put_open_state
(
state
);
state
=
NULL
;
up_read
(
&
clp
->
cl_sem
);
*
res
=
state
;
return
0
;
out_err:
if
(
sp
!=
NULL
)
{
if
(
state
!=
NULL
)
nfs4_put_open_state
(
state
);
up
(
&
sp
->
so_sema
);
nfs4_put_state_owner
(
sp
);
}
if
(
inode
)
{
/* Note: clp->cl_sem must be released before nfs4_put_open_state()! */
up_read
(
&
clp
->
cl_sem
);
if
(
inode
!=
NULL
)
iput
(
inode
);
inode
=
NULL
;
}
/* NOTE: BAD_SEQID means the server and client disagree about the
* book-keeping w.r.t. state-changing operations
* (OPEN/CLOSE/LOCK/LOCKU...)
* It is actually a sign of a bug on the client or on the server.
*
* If we receive a BAD_SEQID error in the particular case of
* doing an OPEN, we assume that nfs4_increment_seqid() will
* have unhashed the old state_owner for us, and that we can
* therefore safely retry using a new one. We should still warn
* the user though...
*/
if
(
status
==
-
NFS4ERR_BAD_SEQID
)
{
printk
(
KERN_WARNING
"NFS: v4 server returned a bad sequence-id error!
\n
"
);
goto
retry
;
}
status
=
nfs4_handle_error
(
server
,
status
);
if
(
!
status
)
goto
retry
;
BUG_ON
(
status
<
-
1000
||
status
>
0
);
out:
return
ERR_PTR
(
status
);
*
res
=
NULL
;
return
status
;
}
int
nfs4_do_setattr
(
struct
nfs_server
*
server
,
struct
nfs_fattr
*
fattr
,
struct
nfs4_state
*
nfs4_do_open
(
struct
inode
*
dir
,
struct
qstr
*
name
,
int
flags
,
struct
iattr
*
sattr
,
struct
rpc_cred
*
cred
)
{
struct
nfs4_exception
exception
=
{
};
struct
nfs4_state
*
res
;
int
status
;
do
{
status
=
_nfs4_do_open
(
dir
,
name
,
flags
,
sattr
,
cred
,
&
res
);
if
(
status
==
0
)
break
;
/* NOTE: BAD_SEQID means the server and client disagree about the
* book-keeping w.r.t. state-changing operations
* (OPEN/CLOSE/LOCK/LOCKU...)
* It is actually a sign of a bug on the client or on the server.
*
* If we receive a BAD_SEQID error in the particular case of
* doing an OPEN, we assume that nfs4_increment_seqid() will
* have unhashed the old state_owner for us, and that we can
* therefore safely retry using a new one. We should still warn
* the user though...
*/
if
(
status
==
-
NFS4ERR_BAD_SEQID
)
{
printk
(
KERN_WARNING
"NFS: v4 server returned a bad sequence-id error!
\n
"
);
exception
.
retry
=
1
;
continue
;
}
res
=
ERR_PTR
(
nfs4_handle_exception
(
NFS_SERVER
(
dir
),
status
,
&
exception
));
}
while
(
exception
.
retry
);
return
res
;
}
static
int
_nfs4_do_setattr
(
struct
nfs_server
*
server
,
struct
nfs_fattr
*
fattr
,
struct
nfs_fh
*
fhandle
,
struct
iattr
*
sattr
,
struct
nfs4_state
*
state
)
{
...
...
@@ -381,9 +420,7 @@ nfs4_do_setattr(struct nfs_server *server, struct nfs_fattr *fattr,
.
rpc_argp
=
&
arg
,
.
rpc_resp
=
&
res
,
};
int
status
;
retry:
fattr
->
valid
=
0
;
if
(
sattr
->
ia_valid
&
ATTR_SIZE
)
...
...
@@ -391,13 +428,22 @@ nfs4_do_setattr(struct nfs_server *server, struct nfs_fattr *fattr,
else
memcpy
(
&
arg
.
stateid
,
&
zero_stateid
,
sizeof
(
arg
.
stateid
));
status
=
rpc_call_sync
(
server
->
client
,
&
msg
,
0
);
if
(
status
)
{
status
=
nfs4_handle_error
(
server
,
status
);
if
(
!
status
)
goto
retry
;
}
return
status
;
return
rpc_call_sync
(
server
->
client
,
&
msg
,
0
);
}
int
nfs4_do_setattr
(
struct
nfs_server
*
server
,
struct
nfs_fattr
*
fattr
,
struct
nfs_fh
*
fhandle
,
struct
iattr
*
sattr
,
struct
nfs4_state
*
state
)
{
struct
nfs4_exception
exception
=
{
};
int
err
;
do
{
err
=
nfs4_handle_exception
(
server
,
_nfs4_do_setattr
(
server
,
fattr
,
fhandle
,
sattr
,
state
),
&
exception
);
}
while
(
exception
.
retry
);
return
err
;
}
/*
...
...
@@ -411,8 +457,7 @@ nfs4_do_setattr(struct nfs_server *server, struct nfs_fattr *fattr,
*
* NOTE: Caller must be holding the sp->so_owner semaphore!
*/
int
nfs4_do_close
(
struct
inode
*
inode
,
struct
nfs4_state
*
state
)
static
int
_nfs4_do_close
(
struct
inode
*
inode
,
struct
nfs4_state
*
state
)
{
struct
nfs4_state_owner
*
sp
=
state
->
owner
;
int
status
=
0
;
...
...
@@ -441,8 +486,27 @@ nfs4_do_close(struct inode *inode, struct nfs4_state *state)
return
status
;
}
int
nfs4_do_downgrade
(
struct
inode
*
inode
,
struct
nfs4_state
*
state
,
mode_t
mode
)
int
nfs4_do_close
(
struct
inode
*
inode
,
struct
nfs4_state
*
state
)
{
struct
nfs_server
*
server
=
NFS_SERVER
(
state
->
inode
);
struct
nfs4_exception
exception
=
{
};
int
err
;
do
{
err
=
_nfs4_do_close
(
inode
,
state
);
switch
(
err
)
{
case
-
NFS4ERR_STALE_STATEID
:
case
-
NFS4ERR_EXPIRED
:
nfs4_schedule_state_recovery
(
server
->
nfs4_state
);
err
=
0
;
default:
state
->
state
=
0
;
}
err
=
nfs4_handle_exception
(
server
,
err
,
&
exception
);
}
while
(
exception
.
retry
);
return
err
;
}
static
int
_nfs4_do_downgrade
(
struct
inode
*
inode
,
struct
nfs4_state
*
state
,
mode_t
mode
)
{
struct
nfs4_state_owner
*
sp
=
state
->
owner
;
int
status
=
0
;
...
...
@@ -467,6 +531,26 @@ nfs4_do_downgrade(struct inode *inode, struct nfs4_state *state, mode_t mode)
return
status
;
}
int
nfs4_do_downgrade
(
struct
inode
*
inode
,
struct
nfs4_state
*
state
,
mode_t
mode
)
{
struct
nfs_server
*
server
=
NFS_SERVER
(
state
->
inode
);
struct
nfs4_exception
exception
=
{
};
int
err
;
do
{
err
=
_nfs4_do_downgrade
(
inode
,
state
,
mode
);
switch
(
err
)
{
case
-
NFS4ERR_STALE_STATEID
:
case
-
NFS4ERR_EXPIRED
:
nfs4_schedule_state_recovery
(
server
->
nfs4_state
);
err
=
0
;
default:
state
->
state
=
mode
;
}
err
=
nfs4_handle_exception
(
server
,
err
,
&
exception
);
}
while
(
exception
.
retry
);
return
err
;
}
struct
inode
*
nfs4_atomic_open
(
struct
inode
*
dir
,
struct
dentry
*
dentry
,
struct
nameidata
*
nd
)
{
...
...
@@ -518,7 +602,7 @@ nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags)
}
static
int
nfs4_server_capabilities
(
struct
nfs_server
*
server
,
struct
nfs_fh
*
fhandle
)
static
int
_
nfs4_server_capabilities
(
struct
nfs_server
*
server
,
struct
nfs_fh
*
fhandle
)
{
struct
nfs4_server_caps_res
res
=
{};
struct
rpc_message
msg
=
{
...
...
@@ -542,7 +626,19 @@ static int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fh
return
status
;
}
static
int
nfs4_lookup_root
(
struct
nfs_server
*
server
,
struct
nfs_fh
*
fhandle
,
static
int
nfs4_server_capabilities
(
struct
nfs_server
*
server
,
struct
nfs_fh
*
fhandle
)
{
struct
nfs4_exception
exception
=
{
};
int
err
;
do
{
err
=
nfs4_handle_exception
(
server
,
_nfs4_server_capabilities
(
server
,
fhandle
),
&
exception
);
}
while
(
exception
.
retry
);
return
err
;
}
static
int
_nfs4_lookup_root
(
struct
nfs_server
*
server
,
struct
nfs_fh
*
fhandle
,
struct
nfs_fsinfo
*
info
)
{
struct
nfs_fattr
*
fattr
=
info
->
fattr
;
...
...
@@ -563,6 +659,19 @@ static int nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle,
return
rpc_call_sync
(
server
->
client
,
&
msg
,
0
);
}
static
int
nfs4_lookup_root
(
struct
nfs_server
*
server
,
struct
nfs_fh
*
fhandle
,
struct
nfs_fsinfo
*
info
)
{
struct
nfs4_exception
exception
=
{
};
int
err
;
do
{
err
=
nfs4_handle_exception
(
server
,
_nfs4_lookup_root
(
server
,
fhandle
,
info
),
&
exception
);
}
while
(
exception
.
retry
);
return
err
;
}
static
int
nfs4_proc_get_root
(
struct
nfs_server
*
server
,
struct
nfs_fh
*
fhandle
,
struct
nfs_fsinfo
*
info
)
{
...
...
@@ -597,6 +706,8 @@ static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
p
=
server
->
mnt_path
;
for
(;;)
{
struct
nfs4_exception
exception
=
{
};
while
(
*
p
==
'/'
)
p
++
;
if
(
!*
p
)
...
...
@@ -606,9 +717,13 @@ static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
p
++
;
q
.
len
=
p
-
q
.
name
;
fattr
->
valid
=
0
;
status
=
rpc_call_sync
(
server
->
client
,
&
msg
,
0
);
if
(
!
status
)
do
{
fattr
->
valid
=
0
;
status
=
nfs4_handle_exception
(
server
,
rpc_call_sync
(
server
->
client
,
&
msg
,
0
),
&
exception
);
}
while
(
exception
.
retry
);
if
(
status
==
0
)
continue
;
if
(
status
==
-
ENOENT
)
{
printk
(
KERN_NOTICE
"NFS: mount path %s does not exist!
\n
"
,
server
->
mnt_path
);
...
...
@@ -621,14 +736,13 @@ static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
if
(
status
==
0
)
status
=
nfs4_do_fsinfo
(
server
,
fhandle
,
info
);
out:
return
nfs4_map_errors
(
status
)
;
return
status
;
}
static
int
nfs4_proc_getattr
(
struct
inode
*
inod
e
,
struct
nfs_fattr
*
fattr
)
static
int
_nfs4_proc_getattr
(
struct
nfs_server
*
server
,
struct
nfs_fh
*
fhandl
e
,
struct
nfs_fattr
*
fattr
)
{
struct
nfs_server
*
server
=
NFS_SERVER
(
inode
);
struct
nfs4_getattr_arg
args
=
{
.
fh
=
NFS_FH
(
inode
)
,
.
fh
=
fhandle
,
.
bitmask
=
server
->
attr_bitmask
,
};
struct
nfs4_getattr_res
res
=
{
...
...
@@ -642,8 +756,19 @@ static int nfs4_proc_getattr(struct inode *inode, struct nfs_fattr *fattr)
};
fattr
->
valid
=
0
;
return
rpc_call_sync
(
server
->
client
,
&
msg
,
0
);
}
return
nfs4_map_errors
(
rpc_call_sync
(
NFS_CLIENT
(
inode
),
&
msg
,
0
));
static
int
nfs4_proc_getattr
(
struct
nfs_server
*
server
,
struct
nfs_fh
*
fhandle
,
struct
nfs_fattr
*
fattr
)
{
struct
nfs4_exception
exception
=
{
};
int
err
;
do
{
err
=
nfs4_handle_exception
(
server
,
_nfs4_proc_getattr
(
server
,
fhandle
,
fattr
),
&
exception
);
}
while
(
exception
.
retry
);
return
err
;
}
/*
...
...
@@ -705,7 +830,7 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
return
status
;
}
static
int
nfs4_proc_lookup
(
struct
inode
*
dir
,
struct
qstr
*
name
,
static
int
_
nfs4_proc_lookup
(
struct
inode
*
dir
,
struct
qstr
*
name
,
struct
nfs_fh
*
fhandle
,
struct
nfs_fattr
*
fattr
)
{
int
status
;
...
...
@@ -731,10 +856,22 @@ static int nfs4_proc_lookup(struct inode *dir, struct qstr *name,
dprintk
(
"NFS call lookup %s
\n
"
,
name
->
name
);
status
=
rpc_call_sync
(
NFS_CLIENT
(
dir
),
&
msg
,
0
);
dprintk
(
"NFS reply lookup: %d
\n
"
,
status
);
return
nfs4_map_errors
(
status
)
;
return
status
;
}
static
int
nfs4_proc_access
(
struct
inode
*
inode
,
struct
nfs_access_entry
*
entry
)
static
int
nfs4_proc_lookup
(
struct
inode
*
dir
,
struct
qstr
*
name
,
struct
nfs_fh
*
fhandle
,
struct
nfs_fattr
*
fattr
)
{
struct
nfs4_exception
exception
=
{
};
int
err
;
do
{
err
=
nfs4_handle_exception
(
NFS_SERVER
(
dir
),
_nfs4_proc_lookup
(
dir
,
name
,
fhandle
,
fattr
),
&
exception
);
}
while
(
exception
.
retry
);
return
err
;
}
static
int
_nfs4_proc_access
(
struct
inode
*
inode
,
struct
nfs_access_entry
*
entry
)
{
struct
nfs4_accessargs
args
=
{
.
fh
=
NFS_FH
(
inode
),
...
...
@@ -775,7 +912,19 @@ static int nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry)
if
(
res
.
access
&
(
NFS4_ACCESS_LOOKUP
|
NFS4_ACCESS_EXECUTE
))
entry
->
mask
|=
MAY_EXEC
;
}
return
nfs4_map_errors
(
status
);
return
status
;
}
static
int
nfs4_proc_access
(
struct
inode
*
inode
,
struct
nfs_access_entry
*
entry
)
{
struct
nfs4_exception
exception
=
{
};
int
err
;
do
{
err
=
nfs4_handle_exception
(
NFS_SERVER
(
inode
),
_nfs4_proc_access
(
inode
,
entry
),
&
exception
);
}
while
(
exception
.
retry
);
return
err
;
}
/*
...
...
@@ -802,7 +951,7 @@ static int nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry)
* Both of these changes to the XDR layer would in fact be quite
* minor, but I decided to leave them for a subsequent patch.
*/
static
int
nfs4_proc_readlink
(
struct
inode
*
inode
,
struct
page
*
page
)
static
int
_
nfs4_proc_readlink
(
struct
inode
*
inode
,
struct
page
*
page
)
{
struct
nfs4_readlink
args
=
{
.
fh
=
NFS_FH
(
inode
),
...
...
@@ -815,11 +964,22 @@ static int nfs4_proc_readlink(struct inode *inode, struct page *page)
.
rpc_resp
=
NULL
,
};
return
nfs4_map_errors
(
rpc_call_sync
(
NFS_CLIENT
(
inode
),
&
msg
,
0
)
);
return
rpc_call_sync
(
NFS_CLIENT
(
inode
),
&
msg
,
0
);
}
static
int
nfs4_proc_read
(
struct
nfs_read_data
*
rdata
,
struct
file
*
filp
)
static
int
nfs4_proc_readlink
(
struct
inode
*
inode
,
struct
page
*
page
)
{
struct
nfs4_exception
exception
=
{
};
int
err
;
do
{
err
=
nfs4_handle_exception
(
NFS_SERVER
(
inode
),
_nfs4_proc_readlink
(
inode
,
page
),
&
exception
);
}
while
(
exception
.
retry
);
return
err
;
}
static
int
_nfs4_proc_read
(
struct
nfs_read_data
*
rdata
)
{
int
flags
=
rdata
->
flags
;
struct
inode
*
inode
=
rdata
->
inode
;
...
...
@@ -829,6 +989,7 @@ nfs4_proc_read(struct nfs_read_data *rdata, struct file *filp)
.
rpc_proc
=
&
nfs4_procedures
[
NFSPROC4_CLNT_READ
],
.
rpc_argp
=
&
rdata
->
args
,
.
rpc_resp
=
&
rdata
->
res
,
.
rpc_cred
=
rdata
->
cred
,
};
unsigned
long
timestamp
=
jiffies
;
int
status
;
...
...
@@ -836,29 +997,27 @@ nfs4_proc_read(struct nfs_read_data *rdata, struct file *filp)
dprintk
(
"NFS call read %d @ %Ld
\n
"
,
rdata
->
args
.
count
,
(
long
long
)
rdata
->
args
.
offset
);
/*
* Try first to use O_RDONLY, then O_RDWR stateid.
*/
if
(
filp
)
{
struct
nfs4_state
*
state
;
state
=
(
struct
nfs4_state
*
)
filp
->
private_data
;
rdata
->
args
.
state
=
state
;
msg
.
rpc_cred
=
state
->
owner
->
so_cred
;
}
else
{
rdata
->
args
.
state
=
NULL
;
msg
.
rpc_cred
=
NFS_I
(
inode
)
->
mm_cred
;
}
fattr
->
valid
=
0
;
status
=
rpc_call_sync
(
server
->
client
,
&
msg
,
flags
);
if
(
!
status
)
renew_lease
(
server
,
timestamp
);
dprintk
(
"NFS reply read: %d
\n
"
,
status
);
return
nfs4_map_errors
(
status
)
;
return
status
;
}
static
int
nfs4_proc_write
(
struct
nfs_write_data
*
wdata
,
struct
file
*
filp
)
static
int
nfs4_proc_read
(
struct
nfs_read_data
*
rdata
)
{
struct
nfs4_exception
exception
=
{
};
int
err
;
do
{
err
=
nfs4_handle_exception
(
NFS_SERVER
(
rdata
->
inode
),
_nfs4_proc_read
(
rdata
),
&
exception
);
}
while
(
exception
.
retry
);
return
err
;
}
static
int
_nfs4_proc_write
(
struct
nfs_write_data
*
wdata
)
{
int
rpcflags
=
wdata
->
flags
;
struct
inode
*
inode
=
wdata
->
inode
;
...
...
@@ -868,33 +1027,32 @@ nfs4_proc_write(struct nfs_write_data *wdata, struct file *filp)
.
rpc_proc
=
&
nfs4_procedures
[
NFSPROC4_CLNT_WRITE
],
.
rpc_argp
=
&
wdata
->
args
,
.
rpc_resp
=
&
wdata
->
res
,
.
rpc_cred
=
wdata
->
cred
,
};
int
status
;
dprintk
(
"NFS call write %d @ %Ld
\n
"
,
wdata
->
args
.
count
,
(
long
long
)
wdata
->
args
.
offset
);
/*
* Try first to use O_WRONLY, then O_RDWR stateid.
*/
if
(
filp
)
{
struct
nfs4_state
*
state
;
state
=
(
struct
nfs4_state
*
)
filp
->
private_data
;
wdata
->
args
.
state
=
state
;
msg
.
rpc_cred
=
state
->
owner
->
so_cred
;
}
else
{
wdata
->
args
.
state
=
NULL
;
msg
.
rpc_cred
=
NFS_I
(
inode
)
->
mm_cred
;
}
fattr
->
valid
=
0
;
status
=
rpc_call_sync
(
server
->
client
,
&
msg
,
rpcflags
);
dprintk
(
"NFS reply write: %d
\n
"
,
status
);
return
nfs4_map_errors
(
status
)
;
return
status
;
}
static
int
nfs4_proc_commit
(
struct
nfs_write_data
*
cdata
,
struct
file
*
filp
)
static
int
nfs4_proc_write
(
struct
nfs_write_data
*
wdata
)
{
struct
nfs4_exception
exception
=
{
};
int
err
;
do
{
err
=
nfs4_handle_exception
(
NFS_SERVER
(
wdata
->
inode
),
_nfs4_proc_write
(
wdata
),
&
exception
);
}
while
(
exception
.
retry
);
return
err
;
}
static
int
_nfs4_proc_commit
(
struct
nfs_write_data
*
cdata
)
{
struct
inode
*
inode
=
cdata
->
inode
;
struct
nfs_fattr
*
fattr
=
cdata
->
res
.
fattr
;
...
...
@@ -903,24 +1061,29 @@ nfs4_proc_commit(struct nfs_write_data *cdata, struct file *filp)
.
rpc_proc
=
&
nfs4_procedures
[
NFSPROC4_CLNT_COMMIT
],
.
rpc_argp
=
&
cdata
->
args
,
.
rpc_resp
=
&
cdata
->
res
,
.
rpc_cred
=
cdata
->
cred
,
};
int
status
;
dprintk
(
"NFS call commit %d @ %Ld
\n
"
,
cdata
->
args
.
count
,
(
long
long
)
cdata
->
args
.
offset
);
/*
* Try first to use O_WRONLY, then O_RDWR stateid.
*/
if
(
filp
)
msg
.
rpc_cred
=
((
struct
nfs4_state
*
)
filp
->
private_data
)
->
owner
->
so_cred
;
else
msg
.
rpc_cred
=
NFS_I
(
inode
)
->
mm_cred
;
fattr
->
valid
=
0
;
status
=
rpc_call_sync
(
server
->
client
,
&
msg
,
0
);
dprintk
(
"NFS reply commit: %d
\n
"
,
status
);
return
nfs4_map_errors
(
status
);
return
status
;
}
static
int
nfs4_proc_commit
(
struct
nfs_write_data
*
cdata
)
{
struct
nfs4_exception
exception
=
{
};
int
err
;
do
{
err
=
nfs4_handle_exception
(
NFS_SERVER
(
cdata
->
inode
),
_nfs4_proc_commit
(
cdata
),
&
exception
);
}
while
(
exception
.
retry
);
return
err
;
}
/*
...
...
@@ -967,7 +1130,7 @@ nfs4_proc_create(struct inode *dir, struct qstr *name, struct iattr *sattr,
return
inode
;
}
static
int
nfs4_proc_remove
(
struct
inode
*
dir
,
struct
qstr
*
name
)
static
int
_
nfs4_proc_remove
(
struct
inode
*
dir
,
struct
qstr
*
name
)
{
struct
nfs4_remove_arg
args
=
{
.
fh
=
NFS_FH
(
dir
),
...
...
@@ -984,7 +1147,19 @@ static int nfs4_proc_remove(struct inode *dir, struct qstr *name)
status
=
rpc_call_sync
(
NFS_CLIENT
(
dir
),
&
msg
,
0
);
if
(
status
==
0
)
update_changeattr
(
dir
,
&
res
);
return
nfs4_map_errors
(
status
);
return
status
;
}
static
int
nfs4_proc_remove
(
struct
inode
*
dir
,
struct
qstr
*
name
)
{
struct
nfs4_exception
exception
=
{
};
int
err
;
do
{
err
=
nfs4_handle_exception
(
NFS_SERVER
(
dir
),
_nfs4_proc_remove
(
dir
,
name
),
&
exception
);
}
while
(
exception
.
retry
);
return
err
;
}
struct
unlink_desc
{
...
...
@@ -1025,7 +1200,7 @@ static int nfs4_proc_unlink_done(struct dentry *dir, struct rpc_task *task)
return
0
;
}
static
int
nfs4_proc_rename
(
struct
inode
*
old_dir
,
struct
qstr
*
old_name
,
static
int
_
nfs4_proc_rename
(
struct
inode
*
old_dir
,
struct
qstr
*
old_name
,
struct
inode
*
new_dir
,
struct
qstr
*
new_name
)
{
struct
nfs4_rename_arg
arg
=
{
...
...
@@ -1048,10 +1223,24 @@ static int nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name,
update_changeattr
(
old_dir
,
&
res
.
old_cinfo
);
update_changeattr
(
new_dir
,
&
res
.
new_cinfo
);
}
return
nfs4_map_errors
(
status
)
;
return
status
;
}
static
int
nfs4_proc_link
(
struct
inode
*
inode
,
struct
inode
*
dir
,
struct
qstr
*
name
)
static
int
nfs4_proc_rename
(
struct
inode
*
old_dir
,
struct
qstr
*
old_name
,
struct
inode
*
new_dir
,
struct
qstr
*
new_name
)
{
struct
nfs4_exception
exception
=
{
};
int
err
;
do
{
err
=
nfs4_handle_exception
(
NFS_SERVER
(
old_dir
),
_nfs4_proc_rename
(
old_dir
,
old_name
,
new_dir
,
new_name
),
&
exception
);
}
while
(
exception
.
retry
);
return
err
;
}
static
int
_nfs4_proc_link
(
struct
inode
*
inode
,
struct
inode
*
dir
,
struct
qstr
*
name
)
{
struct
nfs4_link_arg
arg
=
{
.
fh
=
NFS_FH
(
inode
),
...
...
@@ -1070,10 +1259,22 @@ static int nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *n
if
(
!
status
)
update_changeattr
(
dir
,
&
cinfo
);
return
nfs4_map_errors
(
status
)
;
return
status
;
}
static
int
nfs4_proc_symlink
(
struct
inode
*
dir
,
struct
qstr
*
name
,
static
int
nfs4_proc_link
(
struct
inode
*
inode
,
struct
inode
*
dir
,
struct
qstr
*
name
)
{
struct
nfs4_exception
exception
=
{
};
int
err
;
do
{
err
=
nfs4_handle_exception
(
NFS_SERVER
(
inode
),
_nfs4_proc_link
(
inode
,
dir
,
name
),
&
exception
);
}
while
(
exception
.
retry
);
return
err
;
}
static
int
_nfs4_proc_symlink
(
struct
inode
*
dir
,
struct
qstr
*
name
,
struct
qstr
*
path
,
struct
iattr
*
sattr
,
struct
nfs_fh
*
fhandle
,
struct
nfs_fattr
*
fattr
)
{
...
...
@@ -1106,10 +1307,25 @@ static int nfs4_proc_symlink(struct inode *dir, struct qstr *name,
status
=
rpc_call_sync
(
NFS_CLIENT
(
dir
),
&
msg
,
0
);
if
(
!
status
)
update_changeattr
(
dir
,
&
res
.
dir_cinfo
);
return
nfs4_map_errors
(
status
)
;
return
status
;
}
static
int
nfs4_proc_mkdir
(
struct
inode
*
dir
,
struct
qstr
*
name
,
static
int
nfs4_proc_symlink
(
struct
inode
*
dir
,
struct
qstr
*
name
,
struct
qstr
*
path
,
struct
iattr
*
sattr
,
struct
nfs_fh
*
fhandle
,
struct
nfs_fattr
*
fattr
)
{
struct
nfs4_exception
exception
=
{
};
int
err
;
do
{
err
=
nfs4_handle_exception
(
NFS_SERVER
(
dir
),
_nfs4_proc_symlink
(
dir
,
name
,
path
,
sattr
,
fhandle
,
fattr
),
&
exception
);
}
while
(
exception
.
retry
);
return
err
;
}
static
int
_nfs4_proc_mkdir
(
struct
inode
*
dir
,
struct
qstr
*
name
,
struct
iattr
*
sattr
,
struct
nfs_fh
*
fhandle
,
struct
nfs_fattr
*
fattr
)
{
...
...
@@ -1139,10 +1355,25 @@ static int nfs4_proc_mkdir(struct inode *dir, struct qstr *name,
status
=
rpc_call_sync
(
NFS_CLIENT
(
dir
),
&
msg
,
0
);
if
(
!
status
)
update_changeattr
(
dir
,
&
res
.
dir_cinfo
);
return
nfs4_map_errors
(
status
)
;
return
status
;
}
static
int
nfs4_proc_readdir
(
struct
dentry
*
dentry
,
struct
rpc_cred
*
cred
,
static
int
nfs4_proc_mkdir
(
struct
inode
*
dir
,
struct
qstr
*
name
,
struct
iattr
*
sattr
,
struct
nfs_fh
*
fhandle
,
struct
nfs_fattr
*
fattr
)
{
struct
nfs4_exception
exception
=
{
};
int
err
;
do
{
err
=
nfs4_handle_exception
(
NFS_SERVER
(
dir
),
_nfs4_proc_mkdir
(
dir
,
name
,
sattr
,
fhandle
,
fattr
),
&
exception
);
}
while
(
exception
.
retry
);
return
err
;
}
static
int
_nfs4_proc_readdir
(
struct
dentry
*
dentry
,
struct
rpc_cred
*
cred
,
u64
cookie
,
struct
page
*
page
,
unsigned
int
count
,
int
plus
)
{
struct
inode
*
dir
=
dentry
->
d_inode
;
...
...
@@ -1168,10 +1399,24 @@ static int nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
if
(
status
==
0
)
memcpy
(
NFS_COOKIEVERF
(
dir
),
res
.
verifier
.
data
,
NFS4_VERIFIER_SIZE
);
unlock_kernel
();
return
nfs4_map_errors
(
status
)
;
return
status
;
}
static
int
nfs4_proc_mknod
(
struct
inode
*
dir
,
struct
qstr
*
name
,
static
int
nfs4_proc_readdir
(
struct
dentry
*
dentry
,
struct
rpc_cred
*
cred
,
u64
cookie
,
struct
page
*
page
,
unsigned
int
count
,
int
plus
)
{
struct
nfs4_exception
exception
=
{
};
int
err
;
do
{
err
=
nfs4_handle_exception
(
NFS_SERVER
(
dentry
->
d_inode
),
_nfs4_proc_readdir
(
dentry
,
cred
,
cookie
,
page
,
count
,
plus
),
&
exception
);
}
while
(
exception
.
retry
);
return
err
;
}
static
int
_nfs4_proc_mknod
(
struct
inode
*
dir
,
struct
qstr
*
name
,
struct
iattr
*
sattr
,
dev_t
rdev
,
struct
nfs_fh
*
fh
,
struct
nfs_fattr
*
fattr
)
{
...
...
@@ -1218,10 +1463,25 @@ static int nfs4_proc_mknod(struct inode *dir, struct qstr *name,
status
=
rpc_call_sync
(
NFS_CLIENT
(
dir
),
&
msg
,
0
);
if
(
!
status
)
update_changeattr
(
dir
,
&
res
.
dir_cinfo
);
return
nfs4_map_errors
(
status
);
return
status
;
}
static
int
nfs4_proc_mknod
(
struct
inode
*
dir
,
struct
qstr
*
name
,
struct
iattr
*
sattr
,
dev_t
rdev
,
struct
nfs_fh
*
fh
,
struct
nfs_fattr
*
fattr
)
{
struct
nfs4_exception
exception
=
{
};
int
err
;
do
{
err
=
nfs4_handle_exception
(
NFS_SERVER
(
dir
),
_nfs4_proc_mknod
(
dir
,
name
,
sattr
,
rdev
,
fh
,
fattr
),
&
exception
);
}
while
(
exception
.
retry
);
return
err
;
}
static
int
nfs4_proc_statfs
(
struct
nfs_server
*
server
,
struct
nfs_fh
*
fhandle
,
static
int
_
nfs4_proc_statfs
(
struct
nfs_server
*
server
,
struct
nfs_fh
*
fhandle
,
struct
nfs_fsstat
*
fsstat
)
{
struct
nfs4_statfs_arg
args
=
{
...
...
@@ -1235,10 +1495,22 @@ static int nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle,
};
fsstat
->
fattr
->
valid
=
0
;
return
nfs4_map_errors
(
rpc_call_sync
(
server
->
client
,
&
msg
,
0
));
return
rpc_call_sync
(
server
->
client
,
&
msg
,
0
);
}
static
int
nfs4_proc_statfs
(
struct
nfs_server
*
server
,
struct
nfs_fh
*
fhandle
,
struct
nfs_fsstat
*
fsstat
)
{
struct
nfs4_exception
exception
=
{
};
int
err
;
do
{
err
=
nfs4_handle_exception
(
server
,
_nfs4_proc_statfs
(
server
,
fhandle
,
fsstat
),
&
exception
);
}
while
(
exception
.
retry
);
return
err
;
}
static
int
nfs4_do_fsinfo
(
struct
nfs_server
*
server
,
struct
nfs_fh
*
fhandle
,
static
int
_
nfs4_do_fsinfo
(
struct
nfs_server
*
server
,
struct
nfs_fh
*
fhandle
,
struct
nfs_fsinfo
*
fsinfo
)
{
struct
nfs4_fsinfo_arg
args
=
{
...
...
@@ -1251,16 +1523,29 @@ static int nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle,
.
rpc_resp
=
fsinfo
,
};
return
nfs4_map_errors
(
rpc_call_sync
(
server
->
client
,
&
msg
,
0
));
return
rpc_call_sync
(
server
->
client
,
&
msg
,
0
);
}
static
int
nfs4_do_fsinfo
(
struct
nfs_server
*
server
,
struct
nfs_fh
*
fhandle
,
struct
nfs_fsinfo
*
fsinfo
)
{
struct
nfs4_exception
exception
=
{
};
int
err
;
do
{
err
=
nfs4_handle_exception
(
server
,
_nfs4_do_fsinfo
(
server
,
fhandle
,
fsinfo
),
&
exception
);
}
while
(
exception
.
retry
);
return
err
;
}
static
int
nfs4_proc_fsinfo
(
struct
nfs_server
*
server
,
struct
nfs_fh
*
fhandle
,
struct
nfs_fsinfo
*
fsinfo
)
{
fsinfo
->
fattr
->
valid
=
0
;
return
nfs4_
map_errors
(
nfs4_do_fsinfo
(
server
,
fhandle
,
fsinfo
)
);
return
nfs4_
do_fsinfo
(
server
,
fhandle
,
fsinfo
);
}
static
int
nfs4_proc_pathconf
(
struct
nfs_server
*
server
,
struct
nfs_fh
*
fhandle
,
static
int
_
nfs4_proc_pathconf
(
struct
nfs_server
*
server
,
struct
nfs_fh
*
fhandle
,
struct
nfs_pathconf
*
pathconf
)
{
struct
nfs4_pathconf_arg
args
=
{
...
...
@@ -1280,7 +1565,21 @@ static int nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle,
}
pathconf
->
fattr
->
valid
=
0
;
return
nfs4_map_errors
(
rpc_call_sync
(
server
->
client
,
&
msg
,
0
));
return
rpc_call_sync
(
server
->
client
,
&
msg
,
0
);
}
static
int
nfs4_proc_pathconf
(
struct
nfs_server
*
server
,
struct
nfs_fh
*
fhandle
,
struct
nfs_pathconf
*
pathconf
)
{
struct
nfs4_exception
exception
=
{
};
int
err
;
do
{
err
=
nfs4_handle_exception
(
server
,
_nfs4_proc_pathconf
(
server
,
fhandle
,
pathconf
),
&
exception
);
}
while
(
exception
.
retry
);
return
err
;
}
static
void
...
...
@@ -1471,8 +1770,10 @@ static int
nfs4_proc_file_open
(
struct
inode
*
inode
,
struct
file
*
filp
)
{
struct
dentry
*
dentry
=
filp
->
f_dentry
;
struct
nfs4_state
*
state
;
struct
nfs_open_context
*
ctx
;
struct
nfs4_state
*
state
=
NULL
;
struct
rpc_cred
*
cred
;
int
status
=
-
ENOMEM
;
dprintk
(
"nfs4_proc_file_open: starting on (%.*s/%.*s)
\n
"
,
(
int
)
dentry
->
d_parent
->
d_name
.
len
,
...
...
@@ -1482,21 +1783,28 @@ nfs4_proc_file_open(struct inode *inode, struct file *filp)
/* Find our open stateid */
cred
=
rpcauth_lookupcred
(
NFS_SERVER
(
inode
)
->
client
->
cl_auth
,
0
);
state
=
nfs4_find_state
(
inode
,
cred
,
filp
->
f_mode
);
if
(
unlikely
(
cred
==
NULL
))
return
-
ENOMEM
;
ctx
=
alloc_nfs_open_context
(
dentry
,
cred
);
put_rpccred
(
cred
);
if
(
state
==
NULL
)
{
printk
(
KERN_WARNING
"NFS: v4 raced in function %s
\n
"
,
__FUNCTION__
);
return
-
EIO
;
/* ERACE actually */
}
if
(
unlikely
(
ctx
==
NULL
))
return
-
ENOMEM
;
status
=
-
EIO
;
/* ERACE actually */
state
=
nfs4_find_state
(
inode
,
cred
,
filp
->
f_mode
);
if
(
unlikely
(
state
==
NULL
))
goto
no_state
;
ctx
->
state
=
state
;
nfs4_close_state
(
state
,
filp
->
f_mode
);
if
(
filp
->
f_mode
&
FMODE_WRITE
)
{
lock_kernel
();
nfs_set_mmcred
(
inode
,
state
->
owner
->
so_cred
);
ctx
->
mode
=
filp
->
f_mode
;
nfs_file_set_open_context
(
filp
,
ctx
);
put_nfs_open_context
(
ctx
);
if
(
filp
->
f_mode
&
FMODE_WRITE
)
nfs_begin_data_update
(
inode
);
unlock_kernel
();
}
filp
->
private_data
=
state
;
return
0
;
no_state:
printk
(
KERN_WARNING
"NFS: v4 raced in function %s
\n
"
,
__FUNCTION__
);
put_nfs_open_context
(
ctx
);
return
status
;
}
/*
...
...
@@ -1505,37 +1813,12 @@ nfs4_proc_file_open(struct inode *inode, struct file *filp)
static
int
nfs4_proc_file_release
(
struct
inode
*
inode
,
struct
file
*
filp
)
{
struct
nfs4_state
*
state
=
(
struct
nfs4_state
*
)
filp
->
private_data
;
if
(
state
)
nfs4_close_state
(
state
,
filp
->
f_mode
);
if
(
filp
->
f_mode
&
FMODE_WRITE
)
{
lock_kernel
();
if
(
filp
->
f_mode
&
FMODE_WRITE
)
nfs_end_data_update
(
inode
);
unlock_kernel
();
}
nfs_file_clear_open_context
(
filp
);
return
0
;
}
/*
* Set up the nfspage struct with the right state info and credentials
*/
static
void
nfs4_request_init
(
struct
nfs_page
*
req
,
struct
file
*
filp
)
{
struct
nfs4_state
*
state
;
if
(
!
filp
)
{
req
->
wb_cred
=
get_rpccred
(
NFS_I
(
req
->
wb_inode
)
->
mm_cred
);
req
->
wb_state
=
NULL
;
return
;
}
state
=
(
struct
nfs4_state
*
)
filp
->
private_data
;
req
->
wb_state
=
state
;
req
->
wb_cred
=
get_rpccred
(
state
->
owner
->
so_cred
);
req
->
wb_lockowner
=
current
->
files
;
}
static
int
nfs4_async_handle_error
(
struct
rpc_task
*
task
,
struct
nfs_server
*
server
)
{
...
...
@@ -1549,11 +1832,13 @@ nfs4_async_handle_error(struct rpc_task *task, struct nfs_server *server)
case
-
NFS4ERR_EXPIRED
:
rpc_sleep_on
(
&
clp
->
cl_rpcwaitq
,
task
,
NULL
,
NULL
);
nfs4_schedule_state_recovery
(
clp
);
if
(
test_bit
(
NFS4CLNT_OK
,
&
clp
->
cl_state
))
rpc_wake_up_task
(
task
);
task
->
tk_status
=
0
;
return
-
EAGAIN
;
case
-
NFS4ERR_GRACE
:
case
-
NFS4ERR_DELAY
:
rpc_delay
(
task
,
NFS4_POLL_RETRY_
TIME
);
rpc_delay
(
task
,
NFS4_POLL_RETRY_
MAX
);
task
->
tk_status
=
0
;
return
-
EAGAIN
;
case
-
NFS4ERR_OLD_STATEID
:
...
...
@@ -1564,12 +1849,11 @@ nfs4_async_handle_error(struct rpc_task *task, struct nfs_server *server)
return
0
;
}
int
nfs4_wait_clnt_recover
(
struct
rpc_clnt
*
clnt
,
struct
nfs4_client
*
clp
)
int
nfs4_wait_clnt_recover
(
struct
rpc_clnt
*
clnt
,
struct
nfs4_client
*
clp
)
{
DEFINE_WAIT
(
wait
);
sigset_t
oldset
;
int
interruptible
,
res
;
int
interruptible
,
res
=
0
;
might_sleep
();
...
...
@@ -1577,101 +1861,85 @@ nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs4_client *clp)
interruptible
=
TASK_UNINTERRUPTIBLE
;
if
(
clnt
->
cl_intr
)
interruptible
=
TASK_INTERRUPTIBLE
;
do
{
res
=
0
;
prepare_to_wait
(
&
clp
->
cl_waitq
,
&
wait
,
interruptible
);
nfs4_schedule_state_recovery
(
clp
);
if
(
test_bit
(
NFS4CLNT_OK
,
&
clp
->
cl_state
)
&&
!
test_bit
(
NFS4CLNT_SETUP_STATE
,
&
clp
->
cl_state
))
break
;
if
(
clnt
->
cl_intr
&&
signalled
())
{
res
=
-
ERESTARTSYS
;
break
;
}
prepare_to_wait
(
&
clp
->
cl_waitq
,
&
wait
,
interruptible
);
nfs4_schedule_state_recovery
(
clp
);
if
(
clnt
->
cl_intr
&&
signalled
())
res
=
-
ERESTARTSYS
;
else
if
(
!
test_bit
(
NFS4CLNT_OK
,
&
clp
->
cl_state
))
schedule
();
}
while
(
!
test_bit
(
NFS4CLNT_OK
,
&
clp
->
cl_state
));
finish_wait
(
&
clp
->
cl_waitq
,
&
wait
);
rpc_clnt_sigunmask
(
clnt
,
&
oldset
);
return
res
;
}
static
int
nfs4_delay
(
struct
rpc_clnt
*
clnt
)
static
int
nfs4_delay
(
struct
rpc_clnt
*
clnt
,
long
*
timeout
)
{
sigset_t
oldset
;
int
res
=
0
;
might_sleep
();
if
(
*
timeout
<=
0
)
*
timeout
=
NFS4_POLL_RETRY_MIN
;
if
(
*
timeout
>
NFS4_POLL_RETRY_MAX
)
*
timeout
=
NFS4_POLL_RETRY_MAX
;
rpc_clnt_sigmask
(
clnt
,
&
oldset
);
if
(
clnt
->
cl_intr
)
{
set_current_state
(
TASK_INTERRUPTIBLE
);
schedule_timeout
(
NFS4_POLL_RETRY_TIME
);
schedule_timeout
(
*
timeout
);
if
(
signalled
())
res
=
-
ERESTARTSYS
;
}
else
{
set_current_state
(
TASK_UNINTERRUPTIBLE
);
schedule_timeout
(
NFS4_POLL_RETRY_TIME
);
schedule_timeout
(
*
timeout
);
}
rpc_clnt_sigunmask
(
clnt
,
&
oldset
);
*
timeout
<<=
1
;
return
res
;
}
/* This is the error handling routine for processes that are allowed
* to sleep.
*/
int
nfs4_handle_error
(
struct
nfs_server
*
server
,
int
errorcode
)
int
nfs4_handle_exception
(
struct
nfs_server
*
server
,
int
errorcode
,
struct
nfs4_exception
*
exception
)
{
struct
nfs4_client
*
clp
=
server
->
nfs4_state
;
int
ret
=
errorcode
;
exception
->
retry
=
0
;
switch
(
errorcode
)
{
case
0
:
return
0
;
case
-
NFS4ERR_STALE_CLIENTID
:
case
-
NFS4ERR_STALE_STATEID
:
case
-
NFS4ERR_EXPIRED
:
ret
=
nfs4_wait_clnt_recover
(
server
->
client
,
clp
);
if
(
ret
==
0
)
exception
->
retry
=
1
;
break
;
case
-
NFS4ERR_GRACE
:
case
-
NFS4ERR_DELAY
:
ret
=
nfs4_delay
(
server
->
client
);
ret
=
nfs4_delay
(
server
->
client
,
&
exception
->
timeout
);
if
(
ret
==
0
)
exception
->
retry
=
1
;
break
;
case
-
NFS4ERR_OLD_STATEID
:
ret
=
0
;
if
(
ret
==
0
)
exception
->
retry
=
1
;
}
/* We failed to handle the error */
return
nfs4_map_errors
(
ret
);
}
static
int
nfs4_request_compatible
(
struct
nfs_page
*
req
,
struct
file
*
filp
,
struct
page
*
page
)
{
struct
nfs4_state
*
state
=
NULL
;
struct
rpc_cred
*
cred
=
NULL
;
if
(
req
->
wb_file
!=
filp
)
return
0
;
if
(
req
->
wb_page
!=
page
)
return
0
;
state
=
(
struct
nfs4_state
*
)
filp
->
private_data
;
if
(
req
->
wb_state
!=
state
)
return
0
;
if
(
req
->
wb_lockowner
!=
current
->
files
)
return
0
;
cred
=
state
->
owner
->
so_cred
;
if
(
req
->
wb_cred
!=
cred
)
return
0
;
return
1
;
}
int
nfs4_proc_setclientid
(
struct
nfs4_client
*
clp
,
u32
program
,
unsigned
short
port
)
int
nfs4_proc_setclientid
(
struct
nfs4_client
*
clp
,
u32
program
,
unsigned
short
port
)
{
u32
*
p
;
struct
nfs4_setclientid
setclientid
;
struct
timespec
tv
;
static
nfs4_verifier
sc_verifier
;
static
int
initialized
;
struct
nfs4_setclientid
setclientid
=
{
.
sc_verifier
=
&
sc_verifier
,
.
sc_prog
=
program
,
};
struct
rpc_message
msg
=
{
.
rpc_proc
=
&
nfs4_procedures
[
NFSPROC4_CLNT_SETCLIENTID
],
.
rpc_argp
=
&
setclientid
,
...
...
@@ -1679,15 +1947,24 @@ nfs4_proc_setclientid(struct nfs4_client *clp,
.
rpc_cred
=
clp
->
cl_cred
,
};
tv
=
CURRENT_TIME
;
p
=
(
u32
*
)
setclientid
.
sc_verifier
.
data
;
*
p
++
=
(
u32
)
tv
.
tv_sec
;
*
p
=
(
u32
)
tv
.
tv_nsec
;
setclientid
.
sc_name
=
clp
->
cl_ipaddr
;
sprintf
(
setclientid
.
sc_netid
,
"tcp"
);
sprintf
(
setclientid
.
sc_uaddr
,
"%s.%d.%d"
,
clp
->
cl_ipaddr
,
port
>>
8
,
port
&
255
);
setclientid
.
sc_prog
=
htonl
(
program
);
setclientid
.
sc_cb_ident
=
0
;
if
(
!
initialized
)
{
struct
timespec
boot_time
;
u32
*
p
;
initialized
=
1
;
boot_time
=
CURRENT_TIME
;
p
=
(
u32
*
)
sc_verifier
.
data
;
*
p
++
=
htonl
((
u32
)
boot_time
.
tv_sec
);
*
p
=
htonl
((
u32
)
boot_time
.
tv_nsec
);
}
setclientid
.
sc_name_len
=
scnprintf
(
setclientid
.
sc_name
,
sizeof
(
setclientid
.
sc_name
),
"%s/%u.%u.%u.%u"
,
clp
->
cl_ipaddr
,
NIPQUAD
(
clp
->
cl_addr
.
s_addr
));
setclientid
.
sc_netid_len
=
scnprintf
(
setclientid
.
sc_netid
,
sizeof
(
setclientid
.
sc_netid
),
"tcp"
);
setclientid
.
sc_uaddr_len
=
scnprintf
(
setclientid
.
sc_uaddr
,
sizeof
(
setclientid
.
sc_uaddr
),
"%s.%d.%d"
,
clp
->
cl_ipaddr
,
port
>>
8
,
port
&
255
);
return
rpc_call_sync
(
clp
->
cl_rpcclient
,
&
msg
,
0
);
}
...
...
@@ -1757,8 +2034,7 @@ nfs4_lck_length(struct file_lock *request)
return
request
->
fl_end
-
request
->
fl_start
+
1
;
}
int
nfs4_proc_getlk
(
struct
nfs4_state
*
state
,
int
cmd
,
struct
file_lock
*
request
)
static
int
_nfs4_proc_getlk
(
struct
nfs4_state
*
state
,
int
cmd
,
struct
file_lock
*
request
)
{
struct
inode
*
inode
=
state
->
inode
;
struct
nfs_server
*
server
=
NFS_SERVER
(
inode
);
...
...
@@ -1782,6 +2058,7 @@ nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock *request)
struct
nfs4_lock_state
*
lsp
;
int
status
;
down_read
(
&
clp
->
cl_sem
);
nlo
.
clientid
=
clp
->
cl_clientid
;
down
(
&
state
->
lock_sema
);
lsp
=
nfs4_find_lock_state
(
state
,
request
->
fl_owner
);
...
...
@@ -1815,14 +2092,28 @@ nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock *request)
if
(
lsp
)
nfs4_put_lock_state
(
lsp
);
up
(
&
state
->
lock_sema
);
return
nfs4_map_errors
(
status
);
up_read
(
&
clp
->
cl_sem
);
return
status
;
}
int
nfs4_proc_unlck
(
struct
nfs4_state
*
state
,
int
cmd
,
struct
file_lock
*
request
)
static
int
nfs4_proc_getlk
(
struct
nfs4_state
*
state
,
int
cmd
,
struct
file_lock
*
request
)
{
struct
nfs4_exception
exception
=
{
};
int
err
;
do
{
err
=
nfs4_handle_exception
(
NFS_SERVER
(
state
->
inode
),
_nfs4_proc_getlk
(
state
,
cmd
,
request
),
&
exception
);
}
while
(
exception
.
retry
);
return
err
;
}
static
int
_nfs4_proc_unlck
(
struct
nfs4_state
*
state
,
int
cmd
,
struct
file_lock
*
request
)
{
struct
inode
*
inode
=
state
->
inode
;
struct
nfs_server
*
server
=
NFS_SERVER
(
inode
);
struct
nfs4_client
*
clp
=
server
->
nfs4_state
;
struct
nfs_lockargs
arg
=
{
.
fh
=
NFS_FH
(
inode
),
.
type
=
nfs4_lck_type
(
cmd
,
request
),
...
...
@@ -1842,31 +2133,48 @@ nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *request)
struct
nfs_locku_opargs
luargs
;
int
status
=
0
;
down_read
(
&
clp
->
cl_sem
);
down
(
&
state
->
lock_sema
);
lsp
=
nfs4_find_lock_state
(
state
,
request
->
fl_owner
);
if
(
!
lsp
)
goto
out
;
luargs
.
seqid
=
lsp
->
ls_seqid
;
memcpy
(
&
luargs
.
stateid
,
&
lsp
->
ls_stateid
,
sizeof
(
luargs
.
stateid
));
arg
.
u
.
locku
=
&
luargs
;
status
=
rpc_call_sync
(
server
->
client
,
&
msg
,
0
);
nfs4_increment_lock_seqid
(
status
,
lsp
);
/* We might have lost the locks! */
if
((
lsp
->
ls_flags
&
NFS_LOCK_INITIALIZED
)
!=
0
)
{
luargs
.
seqid
=
lsp
->
ls_seqid
;
memcpy
(
&
luargs
.
stateid
,
&
lsp
->
ls_stateid
,
sizeof
(
luargs
.
stateid
));
arg
.
u
.
locku
=
&
luargs
;
status
=
rpc_call_sync
(
server
->
client
,
&
msg
,
0
);
nfs4_increment_lock_seqid
(
status
,
lsp
);
}
if
(
status
==
0
)
{
memcpy
(
&
lsp
->
ls_stateid
,
&
res
.
u
.
stateid
,
sizeof
(
lsp
->
ls_stateid
));
nfs4_notify_unlck
(
inod
e
,
request
,
lsp
);
nfs4_notify_unlck
(
stat
e
,
request
,
lsp
);
}
nfs4_put_lock_state
(
lsp
);
out:
up
(
&
state
->
lock_sema
);
if
(
status
==
0
)
posix_lock_file
(
request
->
fl_file
,
request
);
return
nfs4_map_errors
(
status
);
up_read
(
&
clp
->
cl_sem
);
return
status
;
}
static
int
nfs4_proc_setlk
(
struct
nfs4_state
*
state
,
int
cmd
,
struct
file_lock
*
request
)
static
int
nfs4_proc_unlck
(
struct
nfs4_state
*
state
,
int
cmd
,
struct
file_lock
*
request
)
{
struct
nfs4_exception
exception
=
{
};
int
err
;
do
{
err
=
nfs4_handle_exception
(
NFS_SERVER
(
state
->
inode
),
_nfs4_proc_unlck
(
state
,
cmd
,
request
),
&
exception
);
}
while
(
exception
.
retry
);
return
err
;
}
static
int
_nfs4_do_setlk
(
struct
nfs4_state
*
state
,
int
cmd
,
struct
file_lock
*
request
,
int
reclaim
)
{
struct
inode
*
inode
=
state
->
inode
;
struct
nfs_server
*
server
=
NFS_SERVER
(
inode
);
...
...
@@ -1887,23 +2195,22 @@ nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request)
.
rpc_cred
=
state
->
owner
->
so_cred
,
};
struct
nfs_lock_opargs
largs
=
{
.
reclaim
=
reclaim
,
.
new_lock_owner
=
0
,
};
int
status
;
down
(
&
state
->
lock_sema
);
lsp
=
nfs4_find_lock_state
(
state
,
request
->
fl_owner
);
if
(
lsp
==
NULL
)
{
lsp
=
nfs4_get_lock_state
(
state
,
request
->
fl_owner
);
if
(
lsp
==
NULL
)
return
-
ENOMEM
;
if
(
!
(
lsp
->
ls_flags
&
NFS_LOCK_INITIALIZED
))
{
struct
nfs4_state_owner
*
owner
=
state
->
owner
;
struct
nfs_open_to_lock
otl
=
{
.
lock_owner
=
{
.
clientid
=
server
->
nfs4_state
->
cl_clientid
,
},
};
status
=
-
ENOMEM
;
lsp
=
nfs4_alloc_lock_state
(
state
,
request
->
fl_owner
);
if
(
!
lsp
)
goto
out
;
otl
.
lock_seqid
=
lsp
->
ls_seqid
;
otl
.
lock_owner
.
id
=
lsp
->
ls_id
;
memcpy
(
&
otl
.
open_stateid
,
&
state
->
stateid
,
sizeof
(
otl
.
open_stateid
));
...
...
@@ -1932,11 +2239,28 @@ nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request)
/* save the returned stateid. */
if
(
status
==
0
)
{
memcpy
(
&
lsp
->
ls_stateid
,
&
res
.
u
.
stateid
,
sizeof
(
nfs4_stateid
));
nfs4_notify_setlk
(
inode
,
request
,
lsp
);
lsp
->
ls_flags
|=
NFS_LOCK_INITIALIZED
;
if
(
!
reclaim
)
nfs4_notify_setlk
(
state
,
request
,
lsp
);
}
else
if
(
status
==
-
NFS4ERR_DENIED
)
status
=
-
EAGAIN
;
nfs4_put_lock_state
(
lsp
);
out:
return
status
;
}
int
nfs4_lock_reclaim
(
struct
nfs4_state
*
state
,
struct
file_lock
*
request
)
{
return
_nfs4_do_setlk
(
state
,
F_SETLK64
,
request
,
1
);
}
static
int
_nfs4_proc_setlk
(
struct
nfs4_state
*
state
,
int
cmd
,
struct
file_lock
*
request
)
{
struct
nfs4_client
*
clp
=
state
->
owner
->
so_client
;
int
status
;
down_read
(
&
clp
->
cl_sem
);
down
(
&
state
->
lock_sema
);
status
=
_nfs4_do_setlk
(
state
,
cmd
,
request
,
0
);
up
(
&
state
->
lock_sema
);
if
(
status
==
0
)
{
/* Note: we always want to sleep here! */
...
...
@@ -1944,19 +2268,34 @@ nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request)
if
(
posix_lock_file_wait
(
request
->
fl_file
,
request
)
<
0
)
printk
(
KERN_WARNING
"%s: VFS is out of sync with lock manager!
\n
"
,
__FUNCTION__
);
}
return
nfs4_map_errors
(
status
);
up_read
(
&
clp
->
cl_sem
);
return
status
;
}
static
int
nfs4_proc_setlk
(
struct
nfs4_state
*
state
,
int
cmd
,
struct
file_lock
*
request
)
{
struct
nfs4_exception
exception
=
{
};
int
err
;
do
{
err
=
nfs4_handle_exception
(
NFS_SERVER
(
state
->
inode
),
_nfs4_proc_setlk
(
state
,
cmd
,
request
),
&
exception
);
}
while
(
exception
.
retry
);
return
err
;
}
static
int
nfs4_proc_lock
(
struct
file
*
filp
,
int
cmd
,
struct
file_lock
*
request
)
{
struct
nfs_open_context
*
ctx
;
struct
nfs4_state
*
state
;
unsigned
long
timeout
=
NFS4_LOCK_MINTIMEOUT
;
int
status
;
/* verify open state */
state
=
(
struct
nfs4_state
*
)
filp
->
private_data
;
BUG_ON
(
!
state
)
;
ctx
=
(
struct
nfs_open_context
*
)
filp
->
private_data
;
state
=
ctx
->
state
;
if
(
request
->
fl_start
<
0
||
request
->
fl_end
<
0
)
return
-
EINVAL
;
...
...
@@ -2016,8 +2355,6 @@ struct nfs_rpc_ops nfs_v4_clientops = {
.
commit_setup
=
nfs4_proc_commit_setup
,
.
file_open
=
nfs4_proc_file_open
,
.
file_release
=
nfs4_proc_file_release
,
.
request_init
=
nfs4_request_init
,
.
request_compatible
=
nfs4_request_compatible
,
.
lock
=
nfs4_proc_lock
,
};
...
...
fs/nfs/nfs4state.c
View file @
477d40b4
...
...
@@ -40,6 +40,7 @@
#include <linux/config.h>
#include <linux/slab.h>
#include <linux/smp_lock.h>
#include <linux/nfs_fs.h>
#include <linux/nfs_idmap.h>
#include <linux/workqueue.h>
...
...
@@ -106,7 +107,7 @@ nfs4_alloc_client(struct in_addr *addr)
INIT_LIST_HEAD
(
&
clp
->
cl_superblocks
);
init_waitqueue_head
(
&
clp
->
cl_waitq
);
rpc_init_wait_queue
(
&
clp
->
cl_rpcwaitq
,
"NFS4 client"
);
clp
->
cl_state
=
1
<<
NFS4CLNT_
NEW
;
clp
->
cl_state
=
1
<<
NFS4CLNT_
OK
;
}
return
clp
;
}
...
...
@@ -169,6 +170,16 @@ nfs4_put_client(struct nfs4_client *clp)
nfs4_free_client
(
clp
);
}
int
nfs4_init_client
(
struct
nfs4_client
*
clp
)
{
int
status
=
nfs4_proc_setclientid
(
clp
,
0
,
0
);
if
(
status
==
0
)
status
=
nfs4_proc_setclientid_confirm
(
clp
);
if
(
status
==
0
)
nfs4_schedule_state_renewal
(
clp
);
return
status
;
}
u32
nfs4_alloc_lockowner_id
(
struct
nfs4_client
*
clp
)
{
...
...
@@ -185,7 +196,6 @@ nfs4_client_grab_unused(struct nfs4_client *clp, struct rpc_cred *cred)
atomic_inc
(
&
sp
->
so_count
);
sp
->
so_cred
=
cred
;
list_move
(
&
sp
->
so_list
,
&
clp
->
cl_state_owners
);
sp
->
so_generation
=
clp
->
cl_generation
;
clp
->
cl_nunused
--
;
}
return
sp
;
...
...
@@ -237,8 +247,11 @@ nfs4_unhash_state_owner(struct nfs4_state_owner *sp)
spin_unlock
(
&
clp
->
cl_lock
);
}
struct
nfs4_state_owner
*
nfs4_get_state_owner
(
struct
nfs_server
*
server
,
struct
rpc_cred
*
cred
)
/*
* Note: must be called with clp->cl_sem held in order to prevent races
* with reboot recovery!
*/
struct
nfs4_state_owner
*
nfs4_get_state_owner
(
struct
nfs_server
*
server
,
struct
rpc_cred
*
cred
)
{
struct
nfs4_client
*
clp
=
server
->
nfs4_state
;
struct
nfs4_state_owner
*
sp
,
*
new
;
...
...
@@ -254,23 +267,23 @@ nfs4_get_state_owner(struct nfs_server *server, struct rpc_cred *cred)
new
->
so_client
=
clp
;
new
->
so_id
=
nfs4_alloc_lockowner_id
(
clp
);
new
->
so_cred
=
cred
;
new
->
so_generation
=
clp
->
cl_generation
;
sp
=
new
;
new
=
NULL
;
}
spin_unlock
(
&
clp
->
cl_lock
);
if
(
new
)
kfree
(
new
);
if
(
sp
)
{
if
(
!
test_bit
(
NFS4CLNT_OK
,
&
clp
->
cl_state
))
nfs4_wait_clnt_recover
(
server
->
client
,
clp
);
}
else
put_rpccred
(
cred
);
return
sp
;
if
(
sp
!=
NULL
)
return
sp
;
put_rpccred
(
cred
);
return
NULL
;
}
void
nfs4_put_state_owner
(
struct
nfs4_state_owner
*
sp
)
/*
* Must be called with clp->cl_sem held in order to avoid races
* with state recovery...
*/
void
nfs4_put_state_owner
(
struct
nfs4_state_owner
*
sp
)
{
struct
nfs4_client
*
clp
=
sp
->
so_client
;
struct
rpc_cred
*
cred
=
sp
->
so_cred
;
...
...
@@ -330,8 +343,6 @@ __nfs4_find_state(struct inode *inode, struct rpc_cred *cred, mode_t mode)
continue
;
if
((
state
->
state
&
mode
)
!=
mode
)
continue
;
/* Add the state to the head of the inode's list */
list_move
(
&
state
->
inode_states
,
&
nfsi
->
open_states
);
atomic_inc
(
&
state
->
count
);
if
(
mode
&
FMODE_READ
)
state
->
nreaders
++
;
...
...
@@ -353,8 +364,6 @@ __nfs4_find_state_byowner(struct inode *inode, struct nfs4_state_owner *owner)
if
(
state
->
nreaders
==
0
&&
state
->
nwriters
==
0
)
continue
;
if
(
state
->
owner
==
owner
)
{
/* Add the state to the head of the inode's list */
list_move
(
&
state
->
inode_states
,
&
nfsi
->
open_states
);
atomic_inc
(
&
state
->
count
);
return
state
;
}
...
...
@@ -411,51 +420,40 @@ nfs4_get_open_state(struct inode *inode, struct nfs4_state_owner *owner)
return
state
;
}
static
void
__nfs4_put_open_state
(
struct
nfs4_state
*
state
)
/*
* Beware! Caller must be holding exactly one
* reference to clp->cl_sem and owner->so_sema!
*/
void
nfs4_put_open_state
(
struct
nfs4_state
*
state
)
{
struct
inode
*
inode
=
state
->
inode
;
struct
nfs4_state_owner
*
owner
=
state
->
owner
;
int
status
=
0
;
if
(
!
atomic_dec_and_lock
(
&
state
->
count
,
&
inode
->
i_lock
))
{
up
(
&
owner
->
so_sema
);
if
(
!
atomic_dec_and_lock
(
&
state
->
count
,
&
inode
->
i_lock
))
return
;
}
if
(
!
list_empty
(
&
state
->
inode_states
))
list_del
(
&
state
->
inode_states
);
spin_unlock
(
&
inode
->
i_lock
);
list_del
(
&
state
->
open_states
);
if
(
state
->
state
!=
0
)
{
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
);
BUG_ON
(
state
->
state
!=
0
);
nfs4_free_open_state
(
state
);
nfs4_put_state_owner
(
owner
);
}
void
nfs4_put_open_state
(
struct
nfs4_state
*
state
)
{
down
(
&
state
->
owner
->
so_sema
);
__nfs4_put_open_state
(
state
);
}
void
nfs4_close_state
(
struct
nfs4_state
*
state
,
mode_t
mode
)
/*
* Beware! Caller must be holding no references to clp->cl_sem!
* of owner->so_sema!
*/
void
nfs4_close_state
(
struct
nfs4_state
*
state
,
mode_t
mode
)
{
struct
inode
*
inode
=
state
->
inode
;
struct
nfs4_state_owner
*
owner
=
state
->
owner
;
struct
nfs4_client
*
clp
=
owner
->
so_client
;
int
newstate
;
int
status
=
0
;
atomic_inc
(
&
owner
->
so_count
);
down_read
(
&
clp
->
cl_sem
);
down
(
&
owner
->
so_sema
);
/* Protect against nfs4_find_state() */
spin_lock
(
&
inode
->
i_lock
);
...
...
@@ -466,29 +464,24 @@ nfs4_close_state(struct nfs4_state *state, mode_t mode)
if
(
state
->
nwriters
==
0
&&
state
->
nreaders
==
0
)
list_del_init
(
&
state
->
inode_states
);
spin_unlock
(
&
inode
->
i_lock
);
do
{
newstate
=
0
;
if
(
state
->
state
==
0
)
break
;
newstate
=
0
;
if
(
state
->
state
!=
0
)
{
if
(
state
->
nreaders
)
newstate
|=
FMODE_READ
;
if
(
state
->
nwriters
)
newstate
|=
FMODE_WRITE
;
if
(
state
->
state
==
newstate
)
break
;
goto
out
;
if
(
newstate
!=
0
)
status
=
nfs4_do_downgrade
(
inode
,
state
,
newstate
);
else
status
=
nfs4_do_close
(
inode
,
state
);
if
(
!
status
)
{
state
->
state
=
newstate
;
break
;
}
up
(
&
owner
->
so_sema
);
status
=
nfs4_handle_error
(
NFS_SERVER
(
inode
),
status
);
down
(
&
owner
->
so_sema
);
}
while
(
!
status
);
__nfs4_put_open_state
(
state
);
}
out:
nfs4_put_open_state
(
state
);
up
(
&
owner
->
so_sema
);
nfs4_put_state_owner
(
owner
);
up_read
(
&
clp
->
cl_sem
);
}
/*
...
...
@@ -524,8 +517,7 @@ nfs4_find_lock_state(struct nfs4_state *state, fl_owner_t fl_owner)
*
* The caller must be holding state->lock_sema
*/
struct
nfs4_lock_state
*
nfs4_alloc_lock_state
(
struct
nfs4_state
*
state
,
fl_owner_t
fl_owner
)
static
struct
nfs4_lock_state
*
nfs4_alloc_lock_state
(
struct
nfs4_state
*
state
,
fl_owner_t
fl_owner
)
{
struct
nfs4_lock_state
*
lsp
;
struct
nfs4_client
*
clp
=
state
->
owner
->
so_client
;
...
...
@@ -533,12 +525,12 @@ nfs4_alloc_lock_state(struct nfs4_state *state, fl_owner_t fl_owner)
lsp
=
kmalloc
(
sizeof
(
*
lsp
),
GFP_KERNEL
);
if
(
lsp
==
NULL
)
return
NULL
;
lsp
->
ls_flags
=
0
;
lsp
->
ls_seqid
=
0
;
/* arbitrary */
lsp
->
ls_id
=
-
1
;
memset
(
lsp
->
ls_stateid
.
data
,
0
,
sizeof
(
lsp
->
ls_stateid
.
data
));
atomic_set
(
&
lsp
->
ls_count
,
1
);
lsp
->
ls_owner
=
fl_owner
;
lsp
->
ls_parent
=
state
;
INIT_LIST_HEAD
(
&
lsp
->
ls_locks
);
spin_lock
(
&
clp
->
cl_lock
);
lsp
->
ls_id
=
nfs4_alloc_lockowner_id
(
clp
);
...
...
@@ -546,6 +538,22 @@ nfs4_alloc_lock_state(struct nfs4_state *state, fl_owner_t fl_owner)
return
lsp
;
}
/*
* Return a compatible lock_state. If no initialized lock_state structure
* exists, return an uninitialized one.
*
* The caller must be holding state->lock_sema and clp->cl_sem
*/
struct
nfs4_lock_state
*
nfs4_get_lock_state
(
struct
nfs4_state
*
state
,
fl_owner_t
owner
)
{
struct
nfs4_lock_state
*
lsp
;
lsp
=
nfs4_find_lock_state
(
state
,
owner
);
if
(
lsp
==
NULL
)
lsp
=
nfs4_alloc_lock_state
(
state
,
owner
);
return
lsp
;
}
/*
* Byte-range lock aware utility to initialize the stateid of read/write
* requests.
...
...
@@ -567,10 +575,9 @@ nfs4_copy_stateid(nfs4_stateid *dst, struct nfs4_state *state, fl_owner_t fl_own
}
/*
* Called with state->lock_sema held.
* Called with state->lock_sema
and clp->cl_sem
held.
*/
void
nfs4_increment_lock_seqid
(
int
status
,
struct
nfs4_lock_state
*
lsp
)
void
nfs4_increment_lock_seqid
(
int
status
,
struct
nfs4_lock_state
*
lsp
)
{
if
(
status
==
NFS_OK
||
seqid_mutating_err
(
-
status
))
lsp
->
ls_seqid
++
;
...
...
@@ -597,13 +604,11 @@ nfs4_check_unlock(struct file_lock *fl, struct file_lock *request)
/*
* Post an initialized lock_state on the state->lock_states list.
*/
void
nfs4_notify_setlk
(
struct
inode
*
inode
,
struct
file_lock
*
request
,
struct
nfs4_lock_state
*
lsp
)
void
nfs4_notify_setlk
(
struct
nfs4_state
*
state
,
struct
file_lock
*
request
,
struct
nfs4_lock_state
*
lsp
)
{
struct
nfs4_state
*
state
=
lsp
->
ls_parent
;
if
(
!
list_empty
(
&
lsp
->
ls_locks
))
return
;
atomic_inc
(
&
lsp
->
ls_count
);
write_lock
(
&
state
->
state_lock
);
list_add
(
&
lsp
->
ls_locks
,
&
state
->
lock_states
);
set_bit
(
LK_STATE_IN_USE
,
&
state
->
flags
);
...
...
@@ -620,9 +625,9 @@ nfs4_notify_setlk(struct inode *inode, struct file_lock *request, struct nfs4_lo
*
*/
void
nfs4_notify_unlck
(
struct
inode
*
inod
e
,
struct
file_lock
*
request
,
struct
nfs4_lock_state
*
lsp
)
nfs4_notify_unlck
(
struct
nfs4_state
*
stat
e
,
struct
file_lock
*
request
,
struct
nfs4_lock_state
*
lsp
)
{
struct
nfs4_state
*
state
=
lsp
->
ls_parent
;
struct
inode
*
inode
=
state
->
inode
;
struct
file_lock
*
fl
;
for
(
fl
=
inode
->
i_flock
;
fl
!=
NULL
;
fl
=
fl
->
fl_next
)
{
...
...
@@ -640,6 +645,7 @@ nfs4_notify_unlck(struct inode *inode, struct file_lock *request, struct nfs4_lo
if
(
list_empty
(
&
state
->
lock_states
))
clear_bit
(
LK_STATE_IN_USE
,
&
state
->
flags
);
write_unlock
(
&
state
->
state_lock
);
nfs4_put_lock_state
(
lsp
);
}
/*
...
...
@@ -651,20 +657,18 @@ nfs4_put_lock_state(struct nfs4_lock_state *lsp)
{
if
(
!
atomic_dec_and_test
(
&
lsp
->
ls_count
))
return
;
if
(
!
list_empty
(
&
lsp
->
ls_locks
))
return
;
BUG_ON
(
!
list_empty
(
&
lsp
->
ls_locks
));
kfree
(
lsp
);
}
/*
* Called with sp->so_sema held.
* Called with sp->so_sema
and clp->cl_sem
held.
*
* Increment the seqid if the OPEN/OPEN_DOWNGRADE/CLOSE succeeded, or
* failed with a seqid incrementing error -
* see comments nfs_fs.h:seqid_mutating_error()
*/
void
nfs4_increment_seqid
(
int
status
,
struct
nfs4_state_owner
*
sp
)
void
nfs4_increment_seqid
(
int
status
,
struct
nfs4_state_owner
*
sp
)
{
if
(
status
==
NFS_OK
||
seqid_mutating_err
(
-
status
))
sp
->
so_seqid
++
;
...
...
@@ -693,21 +697,14 @@ nfs4_recover_state(void *data)
init_completion
(
&
args
.
complete
);
down_read
(
&
clp
->
cl_sem
);
if
(
test_and_set_bit
(
NFS4CLNT_SETUP_STATE
,
&
clp
->
cl_state
))
goto
out_failed
;
if
(
kernel_thread
(
reclaimer
,
&
args
,
CLONE_KERNEL
)
<
0
)
goto
out_failed_clear
;
wait_for_completion
(
&
args
.
complete
);
return
;
out_failed_clear:
smp_mb__before_clear_bit
();
clear_bit
(
NFS4CLNT_SETUP_STATE
,
&
clp
->
cl_state
);
smp_mb__after_clear_bit
();
set_bit
(
NFS4CLNT_OK
,
&
clp
->
cl_state
);
wake_up_all
(
&
clp
->
cl_waitq
);
rpc_wake_up
(
&
clp
->
cl_rpcwaitq
);
out_failed:
up_read
(
&
clp
->
cl_sem
);
}
/*
...
...
@@ -718,24 +715,66 @@ 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
);
if
(
test_and_clear_bit
(
NFS4CLNT_OK
,
&
clp
->
cl_state
))
schedule_work
(
&
clp
->
cl_recoverd
);
}
static
int
nfs4_reclaim_open_state
(
struct
nfs4_state_owner
*
sp
)
static
int
nfs4_reclaim_locks
(
struct
nfs4_state
*
state
)
{
struct
inode
*
inode
=
state
->
inode
;
struct
file_lock
*
fl
;
int
status
=
0
;
for
(
fl
=
inode
->
i_flock
;
fl
!=
0
;
fl
=
fl
->
fl_next
)
{
if
(
!
(
fl
->
fl_flags
&
FL_POSIX
))
continue
;
if
(((
struct
nfs_open_context
*
)
fl
->
fl_file
->
private_data
)
->
state
!=
state
)
continue
;
status
=
nfs4_lock_reclaim
(
state
,
fl
);
if
(
status
>=
0
)
continue
;
switch
(
status
)
{
default:
printk
(
KERN_ERR
"%s: unhandled error %d. Zeroing state
\n
"
,
__FUNCTION__
,
status
);
case
-
NFS4ERR_EXPIRED
:
case
-
NFS4ERR_NO_GRACE
:
case
-
NFS4ERR_RECLAIM_BAD
:
case
-
NFS4ERR_RECLAIM_CONFLICT
:
/* kill_proc(fl->fl_owner, SIGLOST, 1); */
break
;
case
-
NFS4ERR_STALE_CLIENTID
:
goto
out_err
;
}
}
return
0
;
out_err:
return
status
;
}
static
int
nfs4_reclaim_open_state
(
struct
nfs4_state_owner
*
sp
)
{
struct
nfs4_state
*
state
;
struct
nfs4_lock_state
*
lock
;
int
status
=
0
;
list_for_each_entry
(
state
,
&
sp
->
so_states
,
open_states
)
{
if
(
state
->
state
==
0
)
continue
;
status
=
nfs4_open_reclaim
(
sp
,
state
);
if
(
status
>=
0
)
list_for_each_entry
(
lock
,
&
state
->
lock_states
,
ls_locks
)
lock
->
ls_flags
&=
~
NFS_LOCK_INITIALIZED
;
if
(
status
>=
0
)
{
status
=
nfs4_reclaim_locks
(
state
);
if
(
status
<
0
)
goto
out_err
;
list_for_each_entry
(
lock
,
&
state
->
lock_states
,
ls_locks
)
{
if
(
!
(
lock
->
ls_flags
&
NFS_LOCK_INITIALIZED
))
printk
(
"%s: Lock reclaim failed!
\n
"
,
__FUNCTION__
);
}
continue
;
}
switch
(
status
)
{
default:
printk
(
KERN_ERR
"%s: unhandled error %d. Zeroing state
\n
"
,
...
...
@@ -762,75 +801,52 @@ nfs4_reclaim_open_state(struct nfs4_state_owner *sp)
return
status
;
}
static
int
reclaimer
(
void
*
ptr
)
static
int
reclaimer
(
void
*
ptr
)
{
struct
reclaimer_args
*
args
=
(
struct
reclaimer_args
*
)
ptr
;
struct
nfs4_client
*
clp
=
args
->
clp
;
struct
nfs4_state_owner
*
sp
;
int
generation
;
int
status
;
daemonize
(
"%u.%u.%u.%u-reclaim"
,
NIPQUAD
(
clp
->
cl_addr
));
allow_signal
(
SIGKILL
);
atomic_inc
(
&
clp
->
cl_count
);
complete
(
&
args
->
complete
);
/* Ensure exclusive access to NFSv4 state */
lock_kernel
();
down_write
(
&
clp
->
cl_sem
);
/* Are there any NFS mounts out there? */
if
(
list_empty
(
&
clp
->
cl_superblocks
))
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
);
if
(
status
)
goto
out_error
;
status
=
nfs4_proc_setclientid_confirm
(
clp
);
restart_loop:
status
=
nfs4_proc_renew
(
clp
);
if
(
status
==
0
)
goto
out
;
status
=
nfs4_init_client
(
clp
);
if
(
status
)
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
);
/* Note: list is protected by exclusive lock on cl->cl_sem */
list_for_each_entry
(
sp
,
&
clp
->
cl_state_owners
,
so_list
)
{
if
(
sp
->
so_generation
-
generation
>=
0
)
continue
;
atomic_inc
(
&
sp
->
so_count
);
spin_unlock
(
&
clp
->
cl_lock
);
down
(
&
sp
->
so_sema
);
if
(
sp
->
so_generation
-
generation
<
0
)
{
smp_rmb
();
sp
->
so_generation
=
clp
->
cl_generation
;
status
=
nfs4_reclaim_open_state
(
sp
);
}
up
(
&
sp
->
so_sema
);
nfs4_put_state_owner
(
sp
);
status
=
nfs4_reclaim_open_state
(
sp
);
if
(
status
<
0
)
{
if
(
status
==
-
NFS4ERR_STALE_CLIENTID
)
nfs4_schedule_state_recovery
(
clp
)
;
goto
out
;
goto
restart_loop
;
goto
out
_error
;
}
goto
restart_loop
;
}
spin_unlock
(
&
clp
->
cl_lock
);
out:
s
mp_mb__before_clear_bit
(
);
clear_bit
(
NFS4CLNT_SETUP_STATE
,
&
clp
->
cl_state
);
smp_mb__after_clear_bit
();
s
et_bit
(
NFS4CLNT_OK
,
&
clp
->
cl_state
);
up_write
(
&
clp
->
cl_sem
);
unlock_kernel
();
wake_up_all
(
&
clp
->
cl_waitq
);
rpc_wake_up
(
&
clp
->
cl_rpcwaitq
);
nfs4_put_client
(
clp
);
return
0
;
out_error:
printk
(
KERN_WARNING
"Error: state recovery failed on NFSv4 server %u.%u.%u.%u
\n
"
,
NIPQUAD
(
clp
->
cl_addr
.
s_addr
));
up_read
(
&
clp
->
cl_sem
);
printk
(
KERN_WARNING
"Error: state recovery failed on NFSv4 server %u.%u.%u.%u with error %d
\n
"
,
NIPQUAD
(
clp
->
cl_addr
.
s_addr
),
-
status
);
goto
out
;
}
...
...
fs/nfs/nfs4xdr.c
View file @
477d40b4
...
...
@@ -404,6 +404,15 @@ struct compound_hdr {
BUG_ON(!p); \
} while (0)
static
void
encode_string
(
struct
xdr_stream
*
xdr
,
unsigned
int
len
,
const
char
*
str
)
{
uint32_t
*
p
;
p
=
xdr_reserve_space
(
xdr
,
4
+
len
);
BUG_ON
(
p
==
NULL
);
xdr_encode_opaque
(
p
,
str
,
len
);
}
static
int
encode_compound_hdr
(
struct
xdr_stream
*
xdr
,
struct
compound_hdr
*
hdr
)
{
uint32_t
*
p
;
...
...
@@ -903,15 +912,15 @@ static int encode_putrootfh(struct xdr_stream *xdr)
return
0
;
}
static
void
encode_stateid
(
struct
xdr_stream
*
xdr
,
struct
nfs4_state
*
state
,
fl_owner_t
lockowner
)
static
void
encode_stateid
(
struct
xdr_stream
*
xdr
,
const
struct
nfs_open_context
*
ctx
)
{
extern
nfs4_stateid
zero_stateid
;
nfs4_stateid
stateid
;
uint32_t
*
p
;
RESERVE_SPACE
(
16
);
if
(
state
!=
NULL
)
{
nfs4_copy_stateid
(
&
stateid
,
state
,
lockowner
);
if
(
ctx
->
state
!=
NULL
)
{
nfs4_copy_stateid
(
&
stateid
,
ctx
->
state
,
ctx
->
lockowner
);
WRITEMEM
(
stateid
.
data
,
sizeof
(
stateid
.
data
));
}
else
WRITEMEM
(
zero_stateid
.
data
,
sizeof
(
zero_stateid
.
data
));
...
...
@@ -924,7 +933,7 @@ static int encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args)
RESERVE_SPACE
(
4
);
WRITE32
(
OP_READ
);
encode_stateid
(
xdr
,
args
->
state
,
args
->
lockowner
);
encode_stateid
(
xdr
,
args
->
context
);
RESERVE_SPACE
(
12
);
WRITE64
(
args
->
offset
);
...
...
@@ -1047,26 +1056,18 @@ static int encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs *
static
int
encode_setclientid
(
struct
xdr_stream
*
xdr
,
const
struct
nfs4_setclientid
*
setclientid
)
{
uint32_t
total_len
;
uint32_t
len1
,
len2
,
len3
;
uint32_t
*
p
;
len1
=
strlen
(
setclientid
->
sc_name
);
len2
=
strlen
(
setclientid
->
sc_netid
);
len3
=
strlen
(
setclientid
->
sc_uaddr
);
total_len
=
XDR_QUADLEN
(
len1
)
+
XDR_QUADLEN
(
len2
)
+
XDR_QUADLEN
(
len3
);
total_len
=
(
total_len
<<
2
)
+
24
+
sizeof
(
setclientid
->
sc_verifier
.
data
);
RESERVE_SPACE
(
total_len
);
RESERVE_SPACE
(
4
+
sizeof
(
setclientid
->
sc_verifier
->
data
));
WRITE32
(
OP_SETCLIENTID
);
WRITEMEM
(
setclientid
->
sc_verifier
.
data
,
sizeof
(
setclientid
->
sc_verifier
.
data
));
WRITE32
(
len1
);
WRITEMEM
(
setclientid
->
sc_name
,
len1
);
WRITEMEM
(
setclientid
->
sc_verifier
->
data
,
sizeof
(
setclientid
->
sc_verifier
->
data
));
encode_string
(
xdr
,
setclientid
->
sc_name_len
,
setclientid
->
sc_name
);
RESERVE_SPACE
(
4
);
WRITE32
(
setclientid
->
sc_prog
);
WRITE32
(
len2
);
WRITEMEM
(
setclientid
->
sc_netid
,
len2
);
WRITE32
(
len3
);
WRITEMEM
(
setclientid
->
sc_uaddr
,
len3
);
encode_string
(
xdr
,
setclientid
->
sc_netid_len
,
setclientid
->
sc_netid
);
encode_string
(
xdr
,
setclientid
->
sc_uaddr_len
,
setclientid
->
sc_uaddr
);
RESERVE_SPACE
(
4
);
WRITE32
(
setclientid
->
sc_cb_ident
);
return
0
;
...
...
@@ -1091,7 +1092,7 @@ static int encode_write(struct xdr_stream *xdr, const struct nfs_writeargs *args
RESERVE_SPACE
(
4
);
WRITE32
(
OP_WRITE
);
encode_stateid
(
xdr
,
args
->
state
,
args
->
lockowner
);
encode_stateid
(
xdr
,
args
->
context
);
RESERVE_SPACE
(
16
);
WRITE64
(
args
->
offset
);
...
...
@@ -1252,9 +1253,9 @@ static int nfs4_xdr_enc_create(struct rpc_rqst *req, uint32_t *p, const struct n
goto
out
;
if
((
status
=
encode_create
(
&
xdr
,
args
))
!=
0
)
goto
out
;
if
((
status
=
encode_getf
attr
(
&
xdr
,
args
->
bitmask
))
!=
0
)
if
((
status
=
encode_getf
h
(
&
xdr
))
!=
0
)
goto
out
;
status
=
encode_getf
h
(
&
xdr
);
status
=
encode_getf
attr
(
&
xdr
,
args
->
bitmask
);
out:
return
status
;
}
...
...
@@ -1325,10 +1326,10 @@ static int nfs4_xdr_enc_open(struct rpc_rqst *req, uint32_t *p, struct nfs_opena
status
=
encode_open
(
&
xdr
,
args
);
if
(
status
)
goto
out
;
status
=
encode_getf
attr
(
&
xdr
,
args
->
bitmask
);
status
=
encode_getf
h
(
&
xdr
);
if
(
status
)
goto
out
;
status
=
encode_getf
h
(
&
xdr
);
status
=
encode_getf
attr
(
&
xdr
,
args
->
bitmask
);
out:
return
status
;
}
...
...
@@ -3220,9 +3221,11 @@ static int nfs4_xdr_dec_create(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_
goto
out
;
if
((
status
=
decode_create
(
&
xdr
,
&
res
->
dir_cinfo
))
!=
0
)
goto
out
;
if
((
status
=
decode_getf
attr
(
&
xdr
,
res
->
fattr
,
res
->
server
))
!=
0
)
if
((
status
=
decode_getf
h
(
&
xdr
,
res
->
fh
))
!=
0
)
goto
out
;
status
=
decode_getfh
(
&
xdr
,
res
->
fh
);
status
=
decode_getfattr
(
&
xdr
,
res
->
fattr
,
res
->
server
);
if
(
status
==
NFS4ERR_DELAY
)
status
=
0
;
out:
return
status
;
}
...
...
@@ -3296,12 +3299,14 @@ static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_ope
if
(
status
)
goto
out
;
status
=
decode_open
(
&
xdr
,
res
);
if
(
status
)
goto
out
;
status
=
decode_getfattr
(
&
xdr
,
res
->
f_attr
,
res
->
server
);
if
(
status
)
goto
out
;
status
=
decode_getfh
(
&
xdr
,
&
res
->
fh
);
if
(
status
)
goto
out
;
status
=
decode_getfattr
(
&
xdr
,
res
->
f_attr
,
res
->
server
);
if
(
status
==
NFS4ERR_DELAY
)
status
=
0
;
out:
return
status
;
}
...
...
@@ -3347,6 +3352,8 @@ static int nfs4_xdr_dec_open_reclaim(struct rpc_rqst *rqstp, uint32_t *p, struct
if
(
status
)
goto
out
;
status
=
decode_getfattr
(
&
xdr
,
res
->
f_attr
,
res
->
server
);
if
(
status
==
NFS4ERR_DELAY
)
status
=
0
;
out:
return
status
;
}
...
...
@@ -3371,6 +3378,8 @@ static int nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_
if
(
status
)
goto
out
;
status
=
decode_getfattr
(
&
xdr
,
res
->
fattr
,
res
->
server
);
if
(
status
==
NFS4ERR_DELAY
)
status
=
0
;
out:
return
status
;
}
...
...
fs/nfs/pagelist.c
View file @
477d40b4
...
...
@@ -31,7 +31,6 @@ nfs_page_alloc(void)
if
(
p
)
{
memset
(
p
,
0
,
sizeof
(
*
p
));
INIT_LIST_HEAD
(
&
p
->
wb_list
);
init_waitqueue_head
(
&
p
->
wb_wait
);
}
return
p
;
}
...
...
@@ -57,7 +56,7 @@ nfs_page_free(struct nfs_page *p)
* User should ensure it is safe to sleep in this function.
*/
struct
nfs_page
*
nfs_create_request
(
struct
file
*
file
,
struct
inode
*
inode
,
nfs_create_request
(
struct
nfs_open_context
*
ctx
,
struct
inode
*
inode
,
struct
page
*
page
,
unsigned
int
offset
,
unsigned
int
count
)
{
...
...
@@ -89,33 +88,38 @@ nfs_create_request(struct file *file, struct inode *inode,
req
->
wb_offset
=
offset
;
req
->
wb_pgbase
=
offset
;
req
->
wb_bytes
=
count
;
req
->
wb_inode
=
inode
;
atomic_set
(
&
req
->
wb_count
,
1
);
server
->
rpc_ops
->
request_init
(
req
,
file
);
req
->
wb_context
=
get_nfs_open_context
(
ctx
);
return
req
;
}
/**
* nfs_unlock_request - Unlock request and wake up sleepers.
* @req:
*/
void
nfs_unlock_request
(
struct
nfs_page
*
req
)
{
if
(
!
NFS_WBACK_BUSY
(
req
))
{
printk
(
KERN_ERR
"NFS: Invalid unlock attempted
\n
"
);
BUG
();
}
smp_mb__before_clear_bit
();
clear_bit
(
PG_BUSY
,
&
req
->
wb_flags
);
smp_mb__after_clear_bit
();
wake_up_all
(
&
req
->
wb_context
->
waitq
);
nfs_release_request
(
req
);
}
/**
* nfs_clear_request - Free up all resources allocated to the request
* @req:
*
* Release
all
resources associated with a write request after it
* Release
page
resources associated with a write request after it
* has completed.
*/
void
nfs_clear_request
(
struct
nfs_page
*
req
)
{
if
(
req
->
wb_state
)
req
->
wb_state
=
NULL
;
/* Release struct file or cached credential */
if
(
req
->
wb_file
)
{
fput
(
req
->
wb_file
);
req
->
wb_file
=
NULL
;
}
if
(
req
->
wb_cred
)
{
put_rpccred
(
req
->
wb_cred
);
req
->
wb_cred
=
NULL
;
}
if
(
req
->
wb_page
)
{
page_cache_release
(
req
->
wb_page
);
req
->
wb_page
=
NULL
;
...
...
@@ -142,6 +146,7 @@ nfs_release_request(struct nfs_page *req)
/* Release struct file or cached credential */
nfs_clear_request
(
req
);
put_nfs_open_context
(
req
->
wb_context
);
nfs_page_free
(
req
);
}
...
...
@@ -185,12 +190,12 @@ nfs_list_add_request(struct nfs_page *req, struct list_head *head)
int
nfs_wait_on_request
(
struct
nfs_page
*
req
)
{
struct
inode
*
inode
=
req
->
wb_inode
;
struct
inode
*
inode
=
req
->
wb_
context
->
dentry
->
d_
inode
;
struct
rpc_clnt
*
clnt
=
NFS_CLIENT
(
inode
);
if
(
!
NFS_WBACK_BUSY
(
req
))
return
0
;
return
nfs_wait_event
(
clnt
,
req
->
wb_
wait
,
!
NFS_WBACK_BUSY
(
req
));
return
nfs_wait_event
(
clnt
,
req
->
wb_
context
->
waitq
,
!
NFS_WBACK_BUSY
(
req
));
}
/**
...
...
@@ -215,7 +220,11 @@ nfs_coalesce_requests(struct list_head *head, struct list_head *dst,
req
=
nfs_list_entry
(
head
->
next
);
if
(
prev
)
{
if
(
req
->
wb_cred
!=
prev
->
wb_cred
)
if
(
req
->
wb_context
->
cred
!=
prev
->
wb_context
->
cred
)
break
;
if
(
req
->
wb_context
->
lockowner
!=
prev
->
wb_context
->
lockowner
)
break
;
if
(
req
->
wb_context
->
state
!=
prev
->
wb_context
->
state
)
break
;
if
(
req
->
wb_index
!=
(
prev
->
wb_index
+
1
))
break
;
...
...
fs/nfs/proc.c
View file @
477d40b4
...
...
@@ -49,18 +49,6 @@
extern
struct
rpc_procinfo
nfs_procedures
[];
static
struct
rpc_cred
*
nfs_cred
(
struct
inode
*
inode
,
struct
file
*
filp
)
{
struct
rpc_cred
*
cred
=
NULL
;
if
(
filp
)
cred
=
(
struct
rpc_cred
*
)
filp
->
private_data
;
if
(
!
cred
)
cred
=
NFS_I
(
inode
)
->
mm_cred
;
return
cred
;
}
/*
* Bare-bones access to getattr: this is for nfs_read_super.
*/
...
...
@@ -99,14 +87,15 @@ nfs_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
* One function for each procedure in the NFS protocol.
*/
static
int
nfs_proc_getattr
(
struct
inode
*
inode
,
struct
nfs_fattr
*
fattr
)
nfs_proc_getattr
(
struct
nfs_server
*
server
,
struct
nfs_fh
*
fhandle
,
struct
nfs_fattr
*
fattr
)
{
int
status
;
dprintk
(
"NFS call getattr
\n
"
);
fattr
->
valid
=
0
;
status
=
rpc_call
(
NFS_CLIENT
(
inode
)
,
NFSPROC_GETATTR
,
NFS_FH
(
inode
)
,
fattr
,
0
);
status
=
rpc_call
(
server
->
client
,
NFSPROC_GETATTR
,
fhandle
,
fattr
,
0
);
dprintk
(
"NFS reply getattr
\n
"
);
return
status
;
}
...
...
@@ -167,8 +156,7 @@ nfs_proc_readlink(struct inode *inode, struct page *page)
return
status
;
}
static
int
nfs_proc_read
(
struct
nfs_read_data
*
rdata
,
struct
file
*
filp
)
static
int
nfs_proc_read
(
struct
nfs_read_data
*
rdata
)
{
int
flags
=
rdata
->
flags
;
struct
inode
*
inode
=
rdata
->
inode
;
...
...
@@ -177,15 +165,14 @@ nfs_proc_read(struct nfs_read_data *rdata, struct file *filp)
.
rpc_proc
=
&
nfs_procedures
[
NFSPROC_READ
],
.
rpc_argp
=
&
rdata
->
args
,
.
rpc_resp
=
&
rdata
->
res
,
.
rpc_cred
=
rdata
->
cred
,
};
int
status
;
dprintk
(
"NFS call read %d @ %Ld
\n
"
,
rdata
->
args
.
count
,
(
long
long
)
rdata
->
args
.
offset
);
fattr
->
valid
=
0
;
msg
.
rpc_cred
=
nfs_cred
(
inode
,
filp
);
status
=
rpc_call_sync
(
NFS_CLIENT
(
inode
),
&
msg
,
flags
);
if
(
status
>=
0
)
{
nfs_refresh_inode
(
inode
,
fattr
);
/* Emulate the eof flag, which isn't normally needed in NFSv2
...
...
@@ -198,8 +185,7 @@ nfs_proc_read(struct nfs_read_data *rdata, struct file *filp)
return
status
;
}
static
int
nfs_proc_write
(
struct
nfs_write_data
*
wdata
,
struct
file
*
filp
)
static
int
nfs_proc_write
(
struct
nfs_write_data
*
wdata
)
{
int
flags
=
wdata
->
flags
;
struct
inode
*
inode
=
wdata
->
inode
;
...
...
@@ -208,13 +194,13 @@ nfs_proc_write(struct nfs_write_data *wdata, struct file *filp)
.
rpc_proc
=
&
nfs_procedures
[
NFSPROC_WRITE
],
.
rpc_argp
=
&
wdata
->
args
,
.
rpc_resp
=
&
wdata
->
res
,
.
rpc_cred
=
wdata
->
cred
,
};
int
status
;
dprintk
(
"NFS call write %d @ %Ld
\n
"
,
wdata
->
args
.
count
,
(
long
long
)
wdata
->
args
.
offset
);
fattr
->
valid
=
0
;
msg
.
rpc_cred
=
nfs_cred
(
inode
,
filp
);
status
=
rpc_call_sync
(
NFS_CLIENT
(
inode
),
&
msg
,
flags
);
if
(
status
>=
0
)
{
nfs_refresh_inode
(
inode
,
fattr
);
...
...
@@ -621,27 +607,6 @@ nfs_proc_commit_setup(struct nfs_write_data *data, int how)
BUG
();
}
/*
* Set up the nfspage struct with the right credentials
*/
static
void
nfs_request_init
(
struct
nfs_page
*
req
,
struct
file
*
filp
)
{
req
->
wb_cred
=
get_rpccred
(
nfs_cred
(
req
->
wb_inode
,
filp
));
}
static
int
nfs_request_compatible
(
struct
nfs_page
*
req
,
struct
file
*
filp
,
struct
page
*
page
)
{
if
(
req
->
wb_file
!=
filp
)
return
0
;
if
(
req
->
wb_page
!=
page
)
return
0
;
if
(
req
->
wb_cred
!=
nfs_file_cred
(
filp
))
return
0
;
return
1
;
}
static
int
nfs_proc_lock
(
struct
file
*
filp
,
int
cmd
,
struct
file_lock
*
fl
)
{
...
...
@@ -682,7 +647,5 @@ struct nfs_rpc_ops nfs_v2_clientops = {
.
commit_setup
=
nfs_proc_commit_setup
,
.
file_open
=
nfs_open
,
.
file_release
=
nfs_release
,
.
request_init
=
nfs_request_init
,
.
request_compatible
=
nfs_request_compatible
,
.
lock
=
nfs_proc_lock
,
};
fs/nfs/read.c
View file @
477d40b4
...
...
@@ -91,8 +91,8 @@ int nfs_return_empty_page(struct page *page)
/*
* Read a page synchronously.
*/
static
int
nfs_readpage_sync
(
struct
file
*
file
,
struct
inode
*
inode
,
struct
page
*
page
)
static
int
nfs_readpage_sync
(
struct
nfs_open_context
*
ctx
,
struct
inode
*
inode
,
struct
page
*
page
)
{
unsigned
int
rsize
=
NFS_SERVER
(
inode
)
->
rsize
;
unsigned
int
count
=
PAGE_CACHE_SIZE
;
...
...
@@ -105,10 +105,11 @@ nfs_readpage_sync(struct file *file, struct inode *inode, struct page *page)
memset
(
rdata
,
0
,
sizeof
(
*
rdata
));
rdata
->
flags
=
(
IS_SWAPFILE
(
inode
)
?
NFS_RPC_SWAPFLAGS
:
0
);
rdata
->
cred
=
ctx
->
cred
;
rdata
->
inode
=
inode
;
INIT_LIST_HEAD
(
&
rdata
->
pages
);
rdata
->
args
.
fh
=
NFS_FH
(
inode
);
rdata
->
args
.
lockowner
=
current
->
files
;
rdata
->
args
.
context
=
ctx
;
rdata
->
args
.
pages
=
&
page
;
rdata
->
args
.
pgbase
=
0UL
;
rdata
->
args
.
count
=
rsize
;
...
...
@@ -134,7 +135,7 @@ nfs_readpage_sync(struct file *file, struct inode *inode, struct page *page)
rdata
->
args
.
count
);
lock_kernel
();
result
=
NFS_PROTO
(
inode
)
->
read
(
rdata
,
file
);
result
=
NFS_PROTO
(
inode
)
->
read
(
rdata
);
unlock_kernel
();
/*
...
...
@@ -169,8 +170,8 @@ nfs_readpage_sync(struct file *file, struct inode *inode, struct page *page)
return
result
;
}
static
int
nfs_readpage_async
(
struct
file
*
file
,
struct
inode
*
inode
,
struct
page
*
page
)
static
int
nfs_readpage_async
(
struct
nfs_open_context
*
ctx
,
struct
inode
*
inode
,
struct
page
*
page
)
{
LIST_HEAD
(
one_request
);
struct
nfs_page
*
new
;
...
...
@@ -179,7 +180,7 @@ nfs_readpage_async(struct file *file, struct inode *inode, struct page *page)
len
=
nfs_page_length
(
inode
,
page
);
if
(
len
==
0
)
return
nfs_return_empty_page
(
page
);
new
=
nfs_create_request
(
file
,
inode
,
page
,
0
,
len
);
new
=
nfs_create_request
(
ctx
,
inode
,
page
,
0
,
len
);
if
(
IS_ERR
(
new
))
{
unlock_page
(
page
);
return
PTR_ERR
(
new
);
...
...
@@ -202,8 +203,8 @@ static void nfs_readpage_release(struct nfs_page *req)
nfs_unlock_request
(
req
);
dprintk
(
"NFS: read done (%s/%Ld %d@%Ld)
\n
"
,
req
->
wb_inode
->
i_sb
->
s_id
,
(
long
long
)
NFS_FILEID
(
req
->
wb_inode
),
req
->
wb_
context
->
dentry
->
d_
inode
->
i_sb
->
s_id
,
(
long
long
)
NFS_FILEID
(
req
->
wb_
context
->
dentry
->
d_
inode
),
req
->
wb_bytes
,
(
long
long
)
req_offset
(
req
));
}
...
...
@@ -217,16 +218,15 @@ static void nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data,
struct
inode
*
inode
;
data
->
req
=
req
;
data
->
inode
=
inode
=
req
->
wb_inode
;
data
->
cred
=
req
->
wb_cred
;
data
->
inode
=
inode
=
req
->
wb_
context
->
dentry
->
d_
inode
;
data
->
cred
=
req
->
wb_c
ontext
->
c
red
;
data
->
args
.
fh
=
NFS_FH
(
inode
);
data
->
args
.
offset
=
req_offset
(
req
)
+
offset
;
data
->
args
.
pgbase
=
req
->
wb_pgbase
+
offset
;
data
->
args
.
pages
=
data
->
pagevec
;
data
->
args
.
count
=
count
;
data
->
args
.
lockowner
=
req
->
wb_lockowner
;
data
->
args
.
state
=
req
->
wb_state
;
data
->
args
.
context
=
req
->
wb_context
;
data
->
res
.
fattr
=
&
data
->
fattr
;
data
->
res
.
count
=
count
;
...
...
@@ -396,7 +396,7 @@ nfs_pagein_list(struct list_head *head, int rpages)
while
(
!
list_empty
(
head
))
{
pages
+=
nfs_coalesce_requests
(
head
,
&
one_request
,
rpages
);
req
=
nfs_list_entry
(
one_request
.
next
);
error
=
nfs_pagein_one
(
&
one_request
,
req
->
wb_inode
);
error
=
nfs_pagein_one
(
&
one_request
,
req
->
wb_
context
->
dentry
->
d_
inode
);
if
(
error
<
0
)
break
;
}
...
...
@@ -500,9 +500,9 @@ void nfs_readpage_result(struct rpc_task *task)
* - The error flag is set for this page. This happens only when a
* previous async read operation failed.
*/
int
nfs_readpage
(
struct
file
*
file
,
struct
page
*
page
)
int
nfs_readpage
(
struct
file
*
file
,
struct
page
*
page
)
{
struct
nfs_open_context
*
ctx
;
struct
inode
*
inode
=
page
->
mapping
->
host
;
int
error
;
...
...
@@ -519,25 +519,33 @@ nfs_readpage(struct file *file, struct page *page)
if
(
error
)
goto
out_error
;
if
(
file
==
NULL
)
{
ctx
=
nfs_find_open_context
(
inode
,
FMODE_READ
);
if
(
ctx
==
NULL
)
return
-
EBADF
;
}
else
ctx
=
get_nfs_open_context
((
struct
nfs_open_context
*
)
file
->
private_data
);
if
(
!
IS_SYNC
(
inode
))
{
error
=
nfs_readpage_async
(
file
,
inode
,
page
);
error
=
nfs_readpage_async
(
ctx
,
inode
,
page
);
goto
out
;
}
error
=
nfs_readpage_sync
(
file
,
inode
,
page
);
error
=
nfs_readpage_sync
(
ctx
,
inode
,
page
);
if
(
error
<
0
&&
IS_SWAPFILE
(
inode
))
printk
(
"Aiee.. nfs swap-in of page failed!
\n
"
);
out:
put_nfs_open_context
(
ctx
);
return
error
;
out_error:
unlock_page
(
page
);
goto
out
;
return
error
;
}
struct
nfs_readdesc
{
struct
list_head
*
head
;
struct
file
*
filp
;
struct
nfs_open_context
*
ctx
;
};
static
int
...
...
@@ -552,7 +560,7 @@ readpage_async_filler(void *data, struct page *page)
len
=
nfs_page_length
(
inode
,
page
);
if
(
len
==
0
)
return
nfs_return_empty_page
(
page
);
new
=
nfs_create_request
(
desc
->
filp
,
inode
,
page
,
0
,
len
);
new
=
nfs_create_request
(
desc
->
ctx
,
inode
,
page
,
0
,
len
);
if
(
IS_ERR
(
new
))
{
SetPageError
(
page
);
unlock_page
(
page
);
...
...
@@ -565,13 +573,11 @@ readpage_async_filler(void *data, struct page *page)
return
0
;
}
int
nfs_readpages
(
struct
file
*
filp
,
struct
address_space
*
mapping
,
int
nfs_readpages
(
struct
file
*
filp
,
struct
address_space
*
mapping
,
struct
list_head
*
pages
,
unsigned
nr_pages
)
{
LIST_HEAD
(
head
);
struct
nfs_readdesc
desc
=
{
.
filp
=
filp
,
.
head
=
&
head
,
};
struct
inode
*
inode
=
mapping
->
host
;
...
...
@@ -583,12 +589,20 @@ nfs_readpages(struct file *filp, struct address_space *mapping,
(
long
long
)
NFS_FILEID
(
inode
),
nr_pages
);
if
(
filp
==
NULL
)
{
desc
.
ctx
=
nfs_find_open_context
(
inode
,
FMODE_READ
);
if
(
desc
.
ctx
==
NULL
)
return
-
EBADF
;
}
else
desc
.
ctx
=
get_nfs_open_context
((
struct
nfs_open_context
*
)
filp
->
private_data
);
ret
=
read_cache_pages
(
mapping
,
pages
,
readpage_async_filler
,
&
desc
);
if
(
!
list_empty
(
&
head
))
{
int
err
=
nfs_pagein_list
(
&
head
,
server
->
rpages
);
if
(
!
ret
)
ret
=
err
;
}
put_nfs_open_context
(
desc
.
ctx
);
return
ret
;
}
...
...
fs/nfs/write.c
View file @
477d40b4
...
...
@@ -71,7 +71,8 @@
/*
* Local function declarations
*/
static
struct
nfs_page
*
nfs_update_request
(
struct
file
*
,
struct
inode
*
,
static
struct
nfs_page
*
nfs_update_request
(
struct
nfs_open_context
*
,
struct
inode
*
,
struct
page
*
,
unsigned
int
,
unsigned
int
);
static
void
nfs_writeback_done_partial
(
struct
nfs_write_data
*
,
int
);
...
...
@@ -173,7 +174,7 @@ static void nfs_mark_uptodate(struct page *page, unsigned int base, unsigned int
* Write a page synchronously.
* Offset is the data offset within the page.
*/
static
int
nfs_writepage_sync
(
struct
file
*
file
,
struct
inode
*
inode
,
static
int
nfs_writepage_sync
(
struct
nfs_open_context
*
ctx
,
struct
inode
*
inode
,
struct
page
*
page
,
unsigned
int
offset
,
unsigned
int
count
,
int
how
)
{
...
...
@@ -187,9 +188,10 @@ static int nfs_writepage_sync(struct file *file, struct inode *inode,
memset
(
wdata
,
0
,
sizeof
(
*
wdata
));
wdata
->
flags
=
how
;
wdata
->
cred
=
ctx
->
cred
;
wdata
->
inode
=
inode
;
wdata
->
args
.
fh
=
NFS_FH
(
inode
);
wdata
->
args
.
lockowner
=
current
->
files
;
wdata
->
args
.
context
=
ctx
;
wdata
->
args
.
pages
=
&
page
;
wdata
->
args
.
stable
=
NFS_FILE_SYNC
;
wdata
->
args
.
pgbase
=
offset
;
...
...
@@ -208,7 +210,7 @@ static int nfs_writepage_sync(struct file *file, struct inode *inode,
wdata
->
args
.
count
=
count
;
wdata
->
args
.
offset
=
page_offset
(
page
)
+
wdata
->
args
.
pgbase
;
result
=
NFS_PROTO
(
inode
)
->
write
(
wdata
,
file
);
result
=
NFS_PROTO
(
inode
)
->
write
(
wdata
);
if
(
result
<
0
)
{
/* Must mark the page invalid after I/O error */
...
...
@@ -234,20 +236,19 @@ static int nfs_writepage_sync(struct file *file, struct inode *inode,
io_error:
nfs_end_data_update_defer
(
inode
);
if
(
wdata
->
cred
)
put_rpccred
(
wdata
->
cred
);
kfree
(
wdata
);
return
written
?
written
:
result
;
}
static
int
nfs_writepage_async
(
struct
file
*
file
,
struct
inode
*
inode
,
struct
page
*
page
,
unsigned
int
offset
,
unsigned
int
count
)
static
int
nfs_writepage_async
(
struct
nfs_open_context
*
ctx
,
struct
inode
*
inode
,
struct
page
*
page
,
unsigned
int
offset
,
unsigned
int
count
)
{
struct
nfs_page
*
req
;
int
status
;
req
=
nfs_update_request
(
file
,
inode
,
page
,
offset
,
count
);
req
=
nfs_update_request
(
ctx
,
inode
,
page
,
offset
,
count
);
status
=
(
IS_ERR
(
req
))
?
PTR_ERR
(
req
)
:
0
;
if
(
status
<
0
)
goto
out
;
...
...
@@ -274,6 +275,7 @@ static int wb_priority(struct writeback_control *wbc)
*/
int
nfs_writepage
(
struct
page
*
page
,
struct
writeback_control
*
wbc
)
{
struct
nfs_open_context
*
ctx
;
struct
inode
*
inode
=
page
->
mapping
->
host
;
unsigned
long
end_index
;
unsigned
offset
=
PAGE_CACHE_SIZE
;
...
...
@@ -308,16 +310,21 @@ int nfs_writepage(struct page *page, struct writeback_control *wbc)
if
(
page
->
index
>=
end_index
+
1
||
!
offset
)
goto
out
;
do_it:
ctx
=
nfs_find_open_context
(
inode
,
FMODE_WRITE
);
if
(
ctx
==
NULL
)
{
err
=
-
EBADF
;
goto
out
;
}
lock_kernel
();
if
(
!
IS_SYNC
(
inode
)
&&
inode_referenced
)
{
err
=
nfs_writepage_async
(
NULL
,
inode
,
page
,
0
,
offset
);
err
=
nfs_writepage_async
(
ctx
,
inode
,
page
,
0
,
offset
);
if
(
err
>=
0
)
{
err
=
0
;
if
(
wbc
->
for_reclaim
)
nfs_flush_inode
(
inode
,
0
,
0
,
FLUSH_STABLE
);
}
}
else
{
err
=
nfs_writepage_sync
(
NULL
,
inode
,
page
,
0
,
err
=
nfs_writepage_sync
(
ctx
,
inode
,
page
,
0
,
offset
,
priority
);
if
(
err
>=
0
)
{
if
(
err
!=
offset
)
...
...
@@ -326,6 +333,7 @@ int nfs_writepage(struct page *page, struct writeback_control *wbc)
}
}
unlock_kernel
();
put_nfs_open_context
(
ctx
);
out:
unlock_page
(
page
);
if
(
inode_referenced
)
...
...
@@ -396,10 +404,9 @@ nfs_inode_add_request(struct inode *inode, struct nfs_page *req)
/*
* Insert a write request into an inode
*/
static
void
nfs_inode_remove_request
(
struct
nfs_page
*
req
)
static
void
nfs_inode_remove_request
(
struct
nfs_page
*
req
)
{
struct
inode
*
inode
=
req
->
wb_inode
;
struct
inode
*
inode
=
req
->
wb_
context
->
dentry
->
d_
inode
;
struct
nfs_inode
*
nfsi
=
NFS_I
(
inode
);
BUG_ON
(
!
NFS_WBACK_BUSY
(
req
));
...
...
@@ -450,7 +457,7 @@ nfs_find_request(struct inode *inode, unsigned long index)
static
void
nfs_mark_request_dirty
(
struct
nfs_page
*
req
)
{
struct
inode
*
inode
=
req
->
wb_inode
;
struct
inode
*
inode
=
req
->
wb_
context
->
dentry
->
d_
inode
;
struct
nfs_inode
*
nfsi
=
NFS_I
(
inode
);
spin_lock
(
&
nfsi
->
req_lock
);
...
...
@@ -467,7 +474,7 @@ nfs_mark_request_dirty(struct nfs_page *req)
static
inline
int
nfs_dirty_request
(
struct
nfs_page
*
req
)
{
struct
nfs_inode
*
nfsi
=
NFS_I
(
req
->
wb_inode
);
struct
nfs_inode
*
nfsi
=
NFS_I
(
req
->
wb_
context
->
dentry
->
d_
inode
);
return
!
list_empty
(
&
req
->
wb_list
)
&&
req
->
wb_list_head
==
&
nfsi
->
dirty
;
}
...
...
@@ -478,7 +485,7 @@ nfs_dirty_request(struct nfs_page *req)
static
void
nfs_mark_request_commit
(
struct
nfs_page
*
req
)
{
struct
inode
*
inode
=
req
->
wb_inode
;
struct
inode
*
inode
=
req
->
wb_
context
->
dentry
->
d_
inode
;
struct
nfs_inode
*
nfsi
=
NFS_I
(
inode
);
spin_lock
(
&
nfsi
->
req_lock
);
...
...
@@ -619,9 +626,9 @@ static int nfs_wait_on_write_congestion(struct address_space *mapping, int intr)
*
* Note: Should always be called with the Page Lock held!
*/
static
struct
nfs_page
*
nfs_update_request
(
struct
file
*
file
,
struct
inode
*
inode
,
struct
page
*
page
,
unsigned
int
offset
,
unsigned
int
bytes
)
static
struct
nfs_page
*
nfs_update_request
(
struct
nfs_open_context
*
ctx
,
struct
inode
*
inode
,
struct
page
*
page
,
unsigned
int
offset
,
unsigned
int
bytes
)
{
struct
nfs_server
*
server
=
NFS_SERVER
(
inode
);
struct
nfs_inode
*
nfsi
=
NFS_I
(
inode
);
...
...
@@ -669,13 +676,9 @@ nfs_update_request(struct file* file, struct inode *inode, struct page *page,
}
spin_unlock
(
&
nfsi
->
req_lock
);
new
=
nfs_create_request
(
file
,
inode
,
page
,
offset
,
bytes
);
new
=
nfs_create_request
(
ctx
,
inode
,
page
,
offset
,
bytes
);
if
(
IS_ERR
(
new
))
return
new
;
if
(
file
)
{
new
->
wb_file
=
file
;
get_file
(
file
);
}
}
/* We have a request for our page.
...
...
@@ -685,7 +688,7 @@ nfs_update_request(struct file* file, struct inode *inode, struct page *page,
* request.
*/
rqend
=
req
->
wb_offset
+
req
->
wb_bytes
;
if
(
req
->
wb_
file
!=
file
if
(
req
->
wb_
context
!=
ctx
||
req
->
wb_page
!=
page
||
!
nfs_dirty_request
(
req
)
||
offset
>
rqend
||
end
<
req
->
wb_offset
)
{
...
...
@@ -706,9 +709,9 @@ nfs_update_request(struct file* file, struct inode *inode, struct page *page,
return
req
;
}
int
nfs_flush_incompatible
(
struct
file
*
file
,
struct
page
*
page
)
int
nfs_flush_incompatible
(
struct
file
*
file
,
struct
page
*
page
)
{
struct
nfs_open_context
*
ctx
=
(
struct
nfs_open_context
*
)
file
->
private_data
;
struct
inode
*
inode
=
page
->
mapping
->
host
;
struct
nfs_page
*
req
;
int
status
=
0
;
...
...
@@ -722,7 +725,7 @@ nfs_flush_incompatible(struct file *file, struct page *page)
*/
req
=
nfs_find_request
(
inode
,
page
->
index
);
if
(
req
)
{
if
(
!
NFS_PROTO
(
inode
)
->
request_compatible
(
req
,
file
,
page
)
)
if
(
req
->
wb_page
!=
page
||
ctx
!=
req
->
wb_context
)
status
=
nfs_wb_page
(
inode
,
page
);
nfs_release_request
(
req
);
}
...
...
@@ -738,6 +741,7 @@ nfs_flush_incompatible(struct file *file, struct page *page)
int
nfs_updatepage
(
struct
file
*
file
,
struct
page
*
page
,
unsigned
int
offset
,
unsigned
int
count
)
{
struct
nfs_open_context
*
ctx
=
(
struct
nfs_open_context
*
)
file
->
private_data
;
struct
dentry
*
dentry
=
file
->
f_dentry
;
struct
inode
*
inode
=
page
->
mapping
->
host
;
struct
nfs_page
*
req
;
...
...
@@ -748,7 +752,7 @@ int nfs_updatepage(struct file *file, struct page *page,
count
,
(
long
long
)(
page_offset
(
page
)
+
offset
));
if
(
IS_SYNC
(
inode
))
{
status
=
nfs_writepage_sync
(
file
,
inode
,
page
,
offset
,
count
,
0
);
status
=
nfs_writepage_sync
(
ctx
,
inode
,
page
,
offset
,
count
,
0
);
if
(
status
>
0
)
{
if
(
offset
==
0
&&
status
==
PAGE_CACHE_SIZE
)
SetPageUptodate
(
page
);
...
...
@@ -785,7 +789,7 @@ int nfs_updatepage(struct file *file, struct page *page,
* it out now.
*/
do
{
req
=
nfs_update_request
(
file
,
inode
,
page
,
offset
,
count
);
req
=
nfs_update_request
(
ctx
,
inode
,
page
,
offset
,
count
);
status
=
(
IS_ERR
(
req
))
?
PTR_ERR
(
req
)
:
0
;
if
(
status
!=
-
EBUSY
)
break
;
...
...
@@ -861,16 +865,15 @@ static void nfs_write_rpcsetup(struct nfs_page *req,
* NB: take care not to mess about with data->commit et al. */
data
->
req
=
req
;
data
->
inode
=
inode
=
req
->
wb_inode
;
data
->
cred
=
req
->
wb_cred
;
data
->
inode
=
inode
=
req
->
wb_
context
->
dentry
->
d_
inode
;
data
->
cred
=
req
->
wb_c
ontext
->
c
red
;
data
->
args
.
fh
=
NFS_FH
(
inode
);
data
->
args
.
offset
=
req_offset
(
req
)
+
offset
;
data
->
args
.
pgbase
=
req
->
wb_pgbase
+
offset
;
data
->
args
.
pages
=
data
->
pagevec
;
data
->
args
.
count
=
count
;
data
->
args
.
lockowner
=
req
->
wb_lockowner
;
data
->
args
.
state
=
req
->
wb_state
;
data
->
args
.
context
=
req
->
wb_context
;
data
->
res
.
fattr
=
&
data
->
fattr
;
data
->
res
.
count
=
count
;
...
...
@@ -1030,7 +1033,7 @@ nfs_flush_list(struct list_head *head, int wpages, int how)
while
(
!
list_empty
(
head
))
{
pages
+=
nfs_coalesce_requests
(
head
,
&
one_request
,
wpages
);
req
=
nfs_list_entry
(
one_request
.
next
);
error
=
nfs_flush_one
(
&
one_request
,
req
->
wb_inode
,
how
);
error
=
nfs_flush_one
(
&
one_request
,
req
->
wb_
context
->
dentry
->
d_
inode
,
how
);
if
(
error
<
0
)
break
;
}
...
...
@@ -1055,16 +1058,15 @@ static void nfs_writeback_done_partial(struct nfs_write_data *data, int status)
struct
page
*
page
=
req
->
wb_page
;
dprintk
(
"NFS: write (%s/%Ld %d@%Ld)"
,
req
->
wb_inode
->
i_sb
->
s_id
,
(
long
long
)
NFS_FILEID
(
req
->
wb_inode
),
req
->
wb_
context
->
dentry
->
d_
inode
->
i_sb
->
s_id
,
(
long
long
)
NFS_FILEID
(
req
->
wb_
context
->
dentry
->
d_
inode
),
req
->
wb_bytes
,
(
long
long
)
req_offset
(
req
));
if
(
status
<
0
)
{
ClearPageUptodate
(
page
);
SetPageError
(
page
);
if
(
req
->
wb_file
)
req
->
wb_file
->
f_error
=
status
;
req
->
wb_context
->
error
=
status
;
dprintk
(
", error = %d
\n
"
,
status
);
}
else
{
#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
...
...
@@ -1105,16 +1107,15 @@ static void nfs_writeback_done_full(struct nfs_write_data *data, int status)
page
=
req
->
wb_page
;
dprintk
(
"NFS: write (%s/%Ld %d@%Ld)"
,
req
->
wb_inode
->
i_sb
->
s_id
,
(
long
long
)
NFS_FILEID
(
req
->
wb_inode
),
req
->
wb_
context
->
dentry
->
d_
inode
->
i_sb
->
s_id
,
(
long
long
)
NFS_FILEID
(
req
->
wb_
context
->
dentry
->
d_
inode
),
req
->
wb_bytes
,
(
long
long
)
req_offset
(
req
));
if
(
status
<
0
)
{
ClearPageUptodate
(
page
);
SetPageError
(
page
);
if
(
req
->
wb_file
)
req
->
wb_file
->
f_error
=
status
;
req
->
wb_context
->
error
=
status
;
end_page_writeback
(
page
);
nfs_inode_remove_request
(
req
);
dprintk
(
", error = %d
\n
"
,
status
);
...
...
@@ -1233,7 +1234,7 @@ static void nfs_commit_rpcsetup(struct list_head *head,
list_splice_init
(
head
,
&
data
->
pages
);
first
=
nfs_list_entry
(
data
->
pages
.
next
);
last
=
nfs_list_entry
(
data
->
pages
.
prev
);
inode
=
first
->
wb_inode
;
inode
=
first
->
wb_
context
->
dentry
->
d_
inode
;
/*
* Determine the offset range of requests in the COMMIT call.
...
...
@@ -1247,7 +1248,7 @@ static void nfs_commit_rpcsetup(struct list_head *head,
len
=
0
;
data
->
inode
=
inode
;
data
->
cred
=
first
->
wb_cred
;
data
->
cred
=
first
->
wb_c
ontext
->
c
red
;
data
->
args
.
fh
=
NFS_FH
(
data
->
inode
);
data
->
args
.
offset
=
start
;
...
...
@@ -1314,13 +1315,12 @@ nfs_commit_done(struct rpc_task *task)
nfs_list_remove_request
(
req
);
dprintk
(
"NFS: commit (%s/%Ld %d@%Ld)"
,
req
->
wb_inode
->
i_sb
->
s_id
,
(
long
long
)
NFS_FILEID
(
req
->
wb_inode
),
req
->
wb_
context
->
dentry
->
d_
inode
->
i_sb
->
s_id
,
(
long
long
)
NFS_FILEID
(
req
->
wb_
context
->
dentry
->
d_
inode
),
req
->
wb_bytes
,
(
long
long
)
req_offset
(
req
));
if
(
task
->
tk_status
<
0
)
{
if
(
req
->
wb_file
)
req
->
wb_file
->
f_error
=
task
->
tk_status
;
req
->
wb_context
->
error
=
task
->
tk_status
;
nfs_inode_remove_request
(
req
);
dprintk
(
", error = %d
\n
"
,
task
->
tk_status
);
goto
next
;
...
...
include/linux/nfs_fs.h
View file @
477d40b4
...
...
@@ -83,6 +83,20 @@ struct nfs_access_entry {
int
mask
;
};
struct
nfs4_state
;
struct
nfs_open_context
{
atomic_t
count
;
struct
dentry
*
dentry
;
struct
rpc_cred
*
cred
;
struct
nfs4_state
*
state
;
fl_owner_t
lockowner
;
int
mode
;
int
error
;
struct
list_head
list
;
wait_queue_head_t
waitq
;
};
/*
* nfs fs inode data in memory
*/
...
...
@@ -156,8 +170,8 @@ struct nfs_inode {
ncommit
,
npages
;
/*
Credentials for shared mmap
*/
struct
rpc_cred
*
mm_cred
;
/*
Open contexts for shared mmap writes
*/
struct
list_head
open_files
;
wait_queue_head_t
nfs_i_wait
;
...
...
@@ -268,7 +282,6 @@ extern struct inode *nfs_fhget(struct super_block *, struct nfs_fh *,
extern
int
nfs_refresh_inode
(
struct
inode
*
,
struct
nfs_fattr
*
);
extern
int
nfs_getattr
(
struct
vfsmount
*
,
struct
dentry
*
,
struct
kstat
*
);
extern
int
nfs_permission
(
struct
inode
*
,
int
,
struct
nameidata
*
);
extern
void
nfs_set_mmcred
(
struct
inode
*
,
struct
rpc_cred
*
);
extern
int
nfs_open
(
struct
inode
*
,
struct
file
*
);
extern
int
nfs_release
(
struct
inode
*
,
struct
file
*
);
extern
int
__nfs_revalidate_inode
(
struct
nfs_server
*
,
struct
inode
*
);
...
...
@@ -278,6 +291,12 @@ extern void nfs_end_attr_update(struct inode *);
extern
void
nfs_begin_data_update
(
struct
inode
*
);
extern
void
nfs_end_data_update
(
struct
inode
*
);
extern
void
nfs_end_data_update_defer
(
struct
inode
*
);
extern
struct
nfs_open_context
*
alloc_nfs_open_context
(
struct
dentry
*
dentry
,
struct
rpc_cred
*
cred
);
extern
struct
nfs_open_context
*
get_nfs_open_context
(
struct
nfs_open_context
*
ctx
);
extern
void
put_nfs_open_context
(
struct
nfs_open_context
*
ctx
);
extern
void
nfs_file_set_open_context
(
struct
file
*
filp
,
struct
nfs_open_context
*
ctx
);
extern
struct
nfs_open_context
*
nfs_find_open_context
(
struct
inode
*
inode
,
int
mode
);
extern
void
nfs_file_clear_open_context
(
struct
file
*
filp
);
/* linux/net/ipv4/ipconfig.c: trims ip addr off front of name, too. */
extern
u32
root_nfs_parse_addr
(
char
*
name
);
/*__init*/
...
...
@@ -289,16 +308,15 @@ extern struct inode_operations nfs_file_inode_operations;
extern
struct
file_operations
nfs_file_operations
;
extern
struct
address_space_operations
nfs_file_aops
;
static
__inline__
struct
rpc_cred
*
nfs_file_cred
(
struct
file
*
file
)
static
inline
struct
rpc_cred
*
nfs_file_cred
(
struct
file
*
file
)
{
struct
rpc_cred
*
cred
=
NULL
;
if
(
file
)
cred
=
(
struct
rpc_cred
*
)
file
->
private_data
;
#ifdef RPC_DEBUG
BUG_ON
(
cred
&&
cred
->
cr_magic
!=
RPCAUTH_CRED_MAGIC
)
;
#endif
return
cred
;
if
(
file
!=
NULL
)
{
struct
nfs_open_context
*
ctx
;
ctx
=
(
struct
nfs_open_context
*
)
file
->
private_data
;
return
ctx
->
cred
;
}
return
NULL
;
}
/*
...
...
@@ -507,8 +525,6 @@ struct idmap;
enum
nfs4_client_state
{
NFS4CLNT_OK
=
0
,
NFS4CLNT_NEW
,
NFS4CLNT_SETUP_STATE
,
};
/*
...
...
@@ -520,7 +536,6 @@ struct nfs4_client {
u64
cl_clientid
;
/* constant */
nfs4_verifier
cl_confirm
;
unsigned
long
cl_state
;
long
cl_generation
;
u32
cl_lockowner_id
;
...
...
@@ -573,9 +588,7 @@ struct nfs4_state_owner {
u32
so_id
;
/* 32-bit identifier, unique */
struct
semaphore
so_sema
;
u32
so_seqid
;
/* protected by so_sema */
unsigned
int
so_flags
;
/* protected by so_sema */
atomic_t
so_count
;
long
so_generation
;
struct
rpc_cred
*
so_cred
;
/* Associated cred */
struct
list_head
so_states
;
...
...
@@ -596,7 +609,8 @@ struct nfs4_state_owner {
struct
nfs4_lock_state
{
struct
list_head
ls_locks
;
/* Other lock stateids */
fl_owner_t
ls_owner
;
/* POSIX lock owner */
struct
nfs4_state
*
ls_parent
;
/* Parent nfs4_state */
#define NFS_LOCK_INITIALIZED 1
int
ls_flags
;
u32
ls_seqid
;
u32
ls_id
;
nfs4_stateid
ls_stateid
;
...
...
@@ -629,6 +643,11 @@ struct nfs4_state {
};
struct
nfs4_exception
{
long
timeout
;
int
retry
;
};
extern
struct
dentry_operations
nfs4_dentry_operations
;
extern
struct
inode_operations
nfs4_dir_inode_operations
;
...
...
@@ -639,10 +658,12 @@ 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_renew
(
struct
nfs4_client
*
);
extern
int
nfs4_do_close
(
struct
inode
*
,
struct
nfs4_state
*
);
int
nfs4_do_downgrade
(
struct
inode
*
inode
,
struct
nfs4_state
*
state
,
mode_t
mode
);
extern
int
nfs4_do_downgrade
(
struct
inode
*
inode
,
struct
nfs4_state
*
state
,
mode_t
mode
);
extern
int
nfs4_wait_clnt_recover
(
struct
rpc_clnt
*
,
struct
nfs4_client
*
);
extern
struct
inode
*
nfs4_atomic_open
(
struct
inode
*
,
struct
dentry
*
,
struct
nameidata
*
);
extern
int
nfs4_open_revalidate
(
struct
inode
*
,
struct
dentry
*
,
int
);
extern
int
nfs4_handle_exception
(
struct
nfs_server
*
,
int
,
struct
nfs4_exception
*
);
extern
int
nfs4_lock_reclaim
(
struct
nfs4_state
*
state
,
struct
file_lock
*
request
);
/* nfs4renewd.c */
extern
void
nfs4_schedule_state_renewal
(
struct
nfs4_client
*
);
...
...
@@ -654,6 +675,7 @@ extern void init_nfsv4_state(struct nfs_server *);
extern
void
destroy_nfsv4_state
(
struct
nfs_server
*
);
extern
struct
nfs4_client
*
nfs4_get_client
(
struct
in_addr
*
);
extern
void
nfs4_put_client
(
struct
nfs4_client
*
clp
);
extern
int
nfs4_init_client
(
struct
nfs4_client
*
clp
);
extern
u32
nfs4_alloc_lockowner_id
(
struct
nfs4_client
*
);
extern
struct
nfs4_state_owner
*
nfs4_get_state_owner
(
struct
nfs_server
*
,
struct
rpc_cred
*
);
...
...
@@ -663,14 +685,13 @@ extern void nfs4_put_open_state(struct nfs4_state *);
extern
void
nfs4_close_state
(
struct
nfs4_state
*
,
mode_t
);
extern
struct
nfs4_state
*
nfs4_find_state
(
struct
inode
*
,
struct
rpc_cred
*
,
mode_t
mode
);
extern
void
nfs4_increment_seqid
(
int
status
,
struct
nfs4_state_owner
*
sp
);
extern
int
nfs4_handle_error
(
struct
nfs_server
*
,
int
);
extern
void
nfs4_schedule_state_recovery
(
struct
nfs4_client
*
);
extern
struct
nfs4_lock_state
*
nfs4_find_lock_state
(
struct
nfs4_state
*
state
,
fl_owner_t
);
extern
struct
nfs4_lock_state
*
nfs4_
alloc
_lock_state
(
struct
nfs4_state
*
state
,
fl_owner_t
);
extern
struct
nfs4_lock_state
*
nfs4_
get
_lock_state
(
struct
nfs4_state
*
state
,
fl_owner_t
);
extern
void
nfs4_put_lock_state
(
struct
nfs4_lock_state
*
state
);
extern
void
nfs4_increment_lock_seqid
(
int
status
,
struct
nfs4_lock_state
*
ls
);
extern
void
nfs4_notify_setlk
(
struct
inod
e
*
,
struct
file_lock
*
,
struct
nfs4_lock_state
*
);
extern
void
nfs4_notify_unlck
(
struct
inod
e
*
,
struct
file_lock
*
,
struct
nfs4_lock_state
*
);
extern
void
nfs4_notify_setlk
(
struct
nfs4_stat
e
*
,
struct
file_lock
*
,
struct
nfs4_lock_state
*
);
extern
void
nfs4_notify_unlck
(
struct
nfs4_stat
e
*
,
struct
file_lock
*
,
struct
nfs4_lock_state
*
);
extern
void
nfs4_copy_stateid
(
nfs4_stateid
*
,
struct
nfs4_state
*
,
fl_owner_t
);
...
...
@@ -681,6 +702,7 @@ struct nfs4_mount_data;
#define destroy_nfsv4_state(server) do { } while (0)
#define nfs4_put_state_owner(inode, owner) do { } while (0)
#define nfs4_put_open_state(state) do { } while (0)
#define nfs4_close_state(a, b) do { } while (0)
#define nfs4_renewd_prepare_shutdown(server) do { } while (0)
#endif
...
...
include/linux/nfs_page.h
View file @
477d40b4
...
...
@@ -29,14 +29,9 @@
struct
nfs_page
{
struct
list_head
wb_list
,
/* Defines state of page: */
*
wb_list_head
;
/* read/write/commit */
struct
file
*
wb_file
;
fl_owner_t
wb_lockowner
;
struct
inode
*
wb_inode
;
struct
rpc_cred
*
wb_cred
;
struct
nfs4_state
*
wb_state
;
struct
page
*
wb_page
;
/* page to read in/write out */
struct
nfs_open_context
*
wb_context
;
/* File state context info */
atomic_t
wb_complete
;
/* i/os we're waiting for */
wait_queue_head_t
wb_wait
;
/* wait queue */
unsigned
long
wb_index
;
/* Offset >> PAGE_CACHE_SHIFT */
unsigned
int
wb_offset
,
/* Offset & ~PAGE_CACHE_MASK */
wb_pgbase
,
/* Start of page data */
...
...
@@ -50,9 +45,11 @@ struct nfs_page {
#define NFS_NEED_COMMIT(req) (test_bit(PG_NEED_COMMIT,&(req)->wb_flags))
#define NFS_NEED_RESCHED(req) (test_bit(PG_NEED_RESCHED,&(req)->wb_flags))
extern
struct
nfs_page
*
nfs_create_request
(
struct
file
*
,
struct
inode
*
,
struct
page
*
,
unsigned
int
,
unsigned
int
);
extern
struct
nfs_page
*
nfs_create_request
(
struct
nfs_open_context
*
ctx
,
struct
inode
*
inode
,
struct
page
*
page
,
unsigned
int
offset
,
unsigned
int
count
);
extern
void
nfs_clear_request
(
struct
nfs_page
*
req
);
extern
void
nfs_release_request
(
struct
nfs_page
*
req
);
...
...
@@ -64,6 +61,7 @@ extern int nfs_scan_list(struct list_head *, struct list_head *,
extern
int
nfs_coalesce_requests
(
struct
list_head
*
,
struct
list_head
*
,
unsigned
int
);
extern
int
nfs_wait_on_request
(
struct
nfs_page
*
);
extern
void
nfs_unlock_request
(
struct
nfs_page
*
req
);
/*
* Lock the page of an asynchronous request without incrementing the wb_count
...
...
@@ -88,19 +86,6 @@ nfs_lock_request(struct nfs_page *req)
return
1
;
}
static
inline
void
nfs_unlock_request
(
struct
nfs_page
*
req
)
{
if
(
!
NFS_WBACK_BUSY
(
req
))
{
printk
(
KERN_ERR
"NFS: Invalid unlock attempted
\n
"
);
BUG
();
}
smp_mb__before_clear_bit
();
clear_bit
(
PG_BUSY
,
&
req
->
wb_flags
);
smp_mb__after_clear_bit
();
wake_up_all
(
&
req
->
wb_wait
);
nfs_release_request
(
req
);
}
/**
* nfs_list_remove_request - Remove a request from its wb_list
...
...
include/linux/nfs_xdr.h
View file @
477d40b4
...
...
@@ -235,8 +235,7 @@ struct nfs_lockres {
struct
nfs_readargs
{
struct
nfs_fh
*
fh
;
fl_owner_t
lockowner
;
struct
nfs4_state
*
state
;
struct
nfs_open_context
*
context
;
__u64
offset
;
__u32
count
;
unsigned
int
pgbase
;
...
...
@@ -259,8 +258,7 @@ struct nfs_readres {
struct
nfs_writeargs
{
struct
nfs_fh
*
fh
;
fl_owner_t
lockowner
;
struct
nfs4_state
*
state
;
struct
nfs_open_context
*
context
;
__u64
offset
;
__u32
count
;
enum
nfs3_stable_how
stable
;
...
...
@@ -597,13 +595,15 @@ struct nfs4_rename_res {
};
struct
nfs4_setclientid
{
nfs4_verifier
sc_verifier
;
/* request */
char
*
sc_name
;
/* request */
const
nfs4_verifier
*
sc_verifier
;
/* request */
unsigned
int
sc_name_len
;
char
sc_name
[
32
];
/* request */
u32
sc_prog
;
/* request */
unsigned
int
sc_netid_len
;
char
sc_netid
[
4
];
/* request */
unsigned
int
sc_uaddr_len
;
char
sc_uaddr
[
24
];
/* request */
u32
sc_cb_ident
;
/* request */
struct
nfs4_client
*
sc_state
;
/* response */
};
struct
nfs4_statfs_arg
{
...
...
@@ -669,16 +669,17 @@ struct nfs_rpc_ops {
int
(
*
getroot
)
(
struct
nfs_server
*
,
struct
nfs_fh
*
,
struct
nfs_fsinfo
*
);
int
(
*
getattr
)
(
struct
inode
*
,
struct
nfs_fattr
*
);
int
(
*
getattr
)
(
struct
nfs_server
*
,
struct
nfs_fh
*
,
struct
nfs_fattr
*
);
int
(
*
setattr
)
(
struct
dentry
*
,
struct
nfs_fattr
*
,
struct
iattr
*
);
int
(
*
lookup
)
(
struct
inode
*
,
struct
qstr
*
,
struct
nfs_fh
*
,
struct
nfs_fattr
*
);
int
(
*
access
)
(
struct
inode
*
,
struct
nfs_access_entry
*
);
int
(
*
readlink
)(
struct
inode
*
,
struct
page
*
);
int
(
*
read
)
(
struct
nfs_read_data
*
,
struct
file
*
);
int
(
*
write
)
(
struct
nfs_write_data
*
,
struct
file
*
);
int
(
*
commit
)
(
struct
nfs_write_data
*
,
struct
file
*
);
int
(
*
read
)
(
struct
nfs_read_data
*
);
int
(
*
write
)
(
struct
nfs_write_data
*
);
int
(
*
commit
)
(
struct
nfs_write_data
*
);
struct
inode
*
(
*
create
)
(
struct
inode
*
,
struct
qstr
*
,
struct
iattr
*
,
int
);
int
(
*
remove
)
(
struct
inode
*
,
struct
qstr
*
);
...
...
@@ -710,8 +711,6 @@ struct nfs_rpc_ops {
void
(
*
commit_setup
)
(
struct
nfs_write_data
*
,
int
how
);
int
(
*
file_open
)
(
struct
inode
*
,
struct
file
*
);
int
(
*
file_release
)
(
struct
inode
*
,
struct
file
*
);
void
(
*
request_init
)(
struct
nfs_page
*
,
struct
file
*
);
int
(
*
request_compatible
)(
struct
nfs_page
*
,
struct
file
*
,
struct
page
*
);
int
(
*
lock
)(
struct
file
*
,
int
,
struct
file_lock
*
);
};
...
...
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