Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
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