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
b1355604
Commit
b1355604
authored
Apr 10, 2004
by
Trond Myklebust
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
NFSv2/v3/v4: Add support for asynchronous writes even if wsize<PAGE_CACHE_SIZE.
parent
7e19d190
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
297 additions
and
212 deletions
+297
-212
fs/nfs/direct.c
fs/nfs/direct.c
+1
-0
fs/nfs/nfs3proc.c
fs/nfs/nfs3proc.c
+4
-30
fs/nfs/nfs4proc.c
fs/nfs/nfs4proc.c
+10
-59
fs/nfs/nfs4xdr.c
fs/nfs/nfs4xdr.c
+5
-2
fs/nfs/proc.c
fs/nfs/proc.c
+3
-18
fs/nfs/write.c
fs/nfs/write.c
+270
-97
include/linux/nfs_fs.h
include/linux/nfs_fs.h
+0
-2
include/linux/nfs_xdr.h
include/linux/nfs_xdr.h
+4
-4
No files found.
fs/nfs/direct.c
View file @
b1355604
...
...
@@ -259,6 +259,7 @@ nfs_direct_write_seg(struct inode *inode, struct file *file,
.
inode
=
inode
,
.
args
=
{
.
fh
=
NFS_FH
(
inode
),
.
lockowner
=
current
->
files
,
},
.
res
=
{
.
fattr
=
&
wdata
.
fattr
,
...
...
fs/nfs/nfs3proc.c
View file @
b1355604
...
...
@@ -763,11 +763,10 @@ nfs3_write_done(struct rpc_task *task)
}
static
void
nfs3_proc_write_setup
(
struct
nfs_write_data
*
data
,
unsigned
int
count
,
int
how
)
nfs3_proc_write_setup
(
struct
nfs_write_data
*
data
,
int
how
)
{
struct
rpc_task
*
task
=
&
data
->
task
;
struct
inode
*
inode
=
data
->
inode
;
struct
nfs_page
*
req
;
int
stable
;
int
flags
;
struct
rpc_message
msg
=
{
...
...
@@ -784,28 +783,14 @@ nfs3_proc_write_setup(struct nfs_write_data *data, unsigned int count, int how)
stable
=
NFS_DATA_SYNC
;
}
else
stable
=
NFS_UNSTABLE
;
req
=
nfs_list_entry
(
data
->
pages
.
next
);
data
->
args
.
fh
=
NFS_FH
(
inode
);
data
->
args
.
offset
=
req_offset
(
req
);
data
->
args
.
pgbase
=
req
->
wb_pgbase
;
data
->
args
.
count
=
count
;
data
->
args
.
stable
=
stable
;
data
->
args
.
pages
=
data
->
pagevec
;
data
->
res
.
fattr
=
&
data
->
fattr
;
data
->
res
.
count
=
count
;
data
->
res
.
verf
=
&
data
->
verf
;
/* Set the initial flags for the task. */
flags
=
(
how
&
FLUSH_SYNC
)
?
0
:
RPC_TASK_ASYNC
;
/* Finalize the task. */
rpc_init_task
(
task
,
NFS_CLIENT
(
inode
),
nfs3_write_done
,
flags
);
task
->
tk_calldata
=
data
;
/* Release requests */
task
->
tk_release
=
nfs_writedata_release
;
rpc_call_setup
(
&
data
->
task
,
&
msg
,
0
);
rpc_call_setup
(
task
,
&
msg
,
0
);
}
static
void
...
...
@@ -822,7 +807,7 @@ nfs3_commit_done(struct rpc_task *task)
}
static
void
nfs3_proc_commit_setup
(
struct
nfs_write_data
*
data
,
u64
start
,
u32
len
,
int
how
)
nfs3_proc_commit_setup
(
struct
nfs_write_data
*
data
,
int
how
)
{
struct
rpc_task
*
task
=
&
data
->
task
;
struct
inode
*
inode
=
data
->
inode
;
...
...
@@ -834,23 +819,12 @@ nfs3_proc_commit_setup(struct nfs_write_data *data, u64 start, u32 len, int how)
.
rpc_cred
=
data
->
cred
,
};
data
->
args
.
fh
=
NFS_FH
(
data
->
inode
);
data
->
args
.
offset
=
start
;
data
->
args
.
count
=
len
;
data
->
res
.
count
=
len
;
data
->
res
.
fattr
=
&
data
->
fattr
;
data
->
res
.
verf
=
&
data
->
verf
;
/* Set the initial flags for the task. */
flags
=
(
how
&
FLUSH_SYNC
)
?
0
:
RPC_TASK_ASYNC
;
/* Finalize the task. */
rpc_init_task
(
task
,
NFS_CLIENT
(
inode
),
nfs3_commit_done
,
flags
);
task
->
tk_calldata
=
data
;
/* Release requests */
task
->
tk_release
=
nfs_commit_release
;
rpc_call_setup
(
&
data
->
task
,
&
msg
,
0
);
rpc_call_setup
(
task
,
&
msg
,
0
);
}
/*
...
...
fs/nfs/nfs4proc.c
View file @
b1355604
...
...
@@ -1134,10 +1134,10 @@ nfs4_proc_write(struct nfs_write_data *wdata, struct file *filp)
if
(
filp
)
{
struct
nfs4_state
*
state
;
state
=
(
struct
nfs4_state
*
)
filp
->
private_data
;
nfs4_copy_stateid
(
&
wdata
->
args
.
stateid
,
state
,
wdata
->
lockowner
)
;
wdata
->
args
.
state
=
state
;
msg
.
rpc_cred
=
state
->
owner
->
so_cred
;
}
else
{
memcpy
(
&
wdata
->
args
.
stateid
,
&
zero_stateid
,
sizeof
(
wdata
->
args
.
stateid
))
;
wdata
->
args
.
state
=
NULL
;
msg
.
rpc_cred
=
NFS_I
(
inode
)
->
mm_cred
;
}
...
...
@@ -1166,15 +1166,10 @@ nfs4_proc_commit(struct nfs_write_data *cdata, struct file *filp)
/*
* Try first to use O_WRONLY, then O_RDWR stateid.
*/
if
(
filp
)
{
struct
nfs4_state
*
state
;
state
=
(
struct
nfs4_state
*
)
filp
->
private_data
;
nfs4_copy_stateid
(
&
cdata
->
args
.
stateid
,
state
,
cdata
->
lockowner
);
msg
.
rpc_cred
=
state
->
owner
->
so_cred
;
}
else
{
memcpy
(
&
cdata
->
args
.
stateid
,
&
zero_stateid
,
sizeof
(
cdata
->
args
.
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
);
...
...
@@ -1548,20 +1543,6 @@ nfs4_proc_read_setup(struct nfs_read_data *data)
rpc_call_setup
(
task
,
&
msg
,
0
);
}
static
void
nfs4_restart_write
(
struct
rpc_task
*
task
)
{
struct
nfs_write_data
*
data
=
(
struct
nfs_write_data
*
)
task
->
tk_calldata
;
struct
nfs_page
*
req
;
rpc_restart_call
(
task
);
req
=
nfs_list_entry
(
data
->
pages
.
next
);
if
(
req
->
wb_state
)
nfs4_copy_stateid
(
&
data
->
args
.
stateid
,
req
->
wb_state
,
req
->
wb_lockowner
);
else
memcpy
(
&
data
->
args
.
stateid
,
&
zero_stateid
,
sizeof
(
data
->
args
.
stateid
));
}
static
void
nfs4_write_done
(
struct
rpc_task
*
task
)
{
...
...
@@ -1569,7 +1550,7 @@ nfs4_write_done(struct rpc_task *task)
struct
inode
*
inode
=
data
->
inode
;
if
(
nfs4_async_handle_error
(
task
,
NFS_SERVER
(
inode
))
==
-
EAGAIN
)
{
task
->
tk_action
=
nfs4_restart_write
;
rpc_restart_call
(
task
)
;
return
;
}
if
(
task
->
tk_status
>=
0
)
...
...
@@ -1579,7 +1560,7 @@ nfs4_write_done(struct rpc_task *task)
}
static
void
nfs4_proc_write_setup
(
struct
nfs_write_data
*
data
,
unsigned
int
count
,
int
how
)
nfs4_proc_write_setup
(
struct
nfs_write_data
*
data
,
int
how
)
{
struct
rpc_task
*
task
=
&
data
->
task
;
struct
rpc_message
msg
=
{
...
...
@@ -1589,7 +1570,6 @@ nfs4_proc_write_setup(struct nfs_write_data *data, unsigned int count, int how)
.
rpc_cred
=
data
->
cred
,
};
struct
inode
*
inode
=
data
->
inode
;
struct
nfs_page
*
req
=
nfs_list_entry
(
data
->
pages
.
next
);
int
stable
;
int
flags
;
...
...
@@ -1600,33 +1580,15 @@ nfs4_proc_write_setup(struct nfs_write_data *data, unsigned int count, int how)
stable
=
NFS_DATA_SYNC
;
}
else
stable
=
NFS_UNSTABLE
;
data
->
args
.
fh
=
NFS_FH
(
inode
);
data
->
args
.
offset
=
req_offset
(
req
);
data
->
args
.
pgbase
=
req
->
wb_pgbase
;
data
->
args
.
count
=
count
;
data
->
args
.
stable
=
stable
;
data
->
args
.
pages
=
data
->
pagevec
;
data
->
res
.
fattr
=
&
data
->
fattr
;
data
->
res
.
count
=
count
;
data
->
res
.
verf
=
&
data
->
verf
;
data
->
timestamp
=
jiffies
;
data
->
lockowner
=
req
->
wb_lockowner
;
if
(
req
->
wb_state
)
nfs4_copy_stateid
(
&
data
->
args
.
stateid
,
req
->
wb_state
,
req
->
wb_lockowner
);
else
memcpy
(
&
data
->
args
.
stateid
,
&
zero_stateid
,
sizeof
(
data
->
args
.
stateid
));
data
->
timestamp
=
jiffies
;
/* Set the initial flags for the task. */
flags
=
(
how
&
FLUSH_SYNC
)
?
0
:
RPC_TASK_ASYNC
;
/* Finalize the task. */
rpc_init_task
(
task
,
NFS_CLIENT
(
inode
),
nfs4_write_done
,
flags
);
task
->
tk_calldata
=
data
;
/* Release requests */
task
->
tk_release
=
nfs_writedata_release
;
rpc_call_setup
(
task
,
&
msg
,
0
);
}
...
...
@@ -1637,7 +1599,7 @@ nfs4_commit_done(struct rpc_task *task)
struct
inode
*
inode
=
data
->
inode
;
if
(
nfs4_async_handle_error
(
task
,
NFS_SERVER
(
inode
))
==
-
EAGAIN
)
{
task
->
tk_action
=
nfs4_restart_write
;
rpc_restart_call
(
task
)
;
return
;
}
/* Call back common NFS writeback processing */
...
...
@@ -1645,7 +1607,7 @@ nfs4_commit_done(struct rpc_task *task)
}
static
void
nfs4_proc_commit_setup
(
struct
nfs_write_data
*
data
,
u64
start
,
u32
len
,
int
how
)
nfs4_proc_commit_setup
(
struct
nfs_write_data
*
data
,
int
how
)
{
struct
rpc_task
*
task
=
&
data
->
task
;
struct
rpc_message
msg
=
{
...
...
@@ -1657,22 +1619,11 @@ nfs4_proc_commit_setup(struct nfs_write_data *data, u64 start, u32 len, int how)
struct
inode
*
inode
=
data
->
inode
;
int
flags
;
data
->
args
.
fh
=
NFS_FH
(
data
->
inode
);
data
->
args
.
offset
=
start
;
data
->
args
.
count
=
len
;
data
->
res
.
count
=
len
;
data
->
res
.
fattr
=
&
data
->
fattr
;
data
->
res
.
verf
=
&
data
->
verf
;
/* Set the initial flags for the task. */
flags
=
(
how
&
FLUSH_SYNC
)
?
0
:
RPC_TASK_ASYNC
;
/* Finalize the task. */
rpc_init_task
(
task
,
NFS_CLIENT
(
inode
),
nfs4_commit_done
,
flags
);
task
->
tk_calldata
=
data
;
/* Release requests */
task
->
tk_release
=
nfs_commit_release
;
rpc_call_setup
(
task
,
&
msg
,
0
);
}
...
...
fs/nfs/nfs4xdr.c
View file @
b1355604
...
...
@@ -1075,9 +1075,12 @@ encode_write(struct xdr_stream *xdr, struct nfs_writeargs *args)
{
uint32_t
*
p
;
RESERVE_SPACE
(
36
);
RESERVE_SPACE
(
4
);
WRITE32
(
OP_WRITE
);
WRITEMEM
(
args
->
stateid
.
data
,
sizeof
(
args
->
stateid
.
data
));
encode_stateid
(
xdr
,
args
->
state
,
args
->
lockowner
);
RESERVE_SPACE
(
16
);
WRITE64
(
args
->
offset
);
WRITE32
(
args
->
stable
);
WRITE32
(
args
->
count
);
...
...
fs/nfs/proc.c
View file @
b1355604
...
...
@@ -590,11 +590,10 @@ nfs_write_done(struct rpc_task *task)
}
static
void
nfs_proc_write_setup
(
struct
nfs_write_data
*
data
,
unsigned
int
count
,
int
how
)
nfs_proc_write_setup
(
struct
nfs_write_data
*
data
,
int
how
)
{
struct
rpc_task
*
task
=
&
data
->
task
;
struct
inode
*
inode
=
data
->
inode
;
struct
nfs_page
*
req
;
int
flags
;
struct
rpc_message
msg
=
{
.
rpc_proc
=
&
nfs_procedures
[
NFSPROC_WRITE
],
...
...
@@ -604,32 +603,18 @@ nfs_proc_write_setup(struct nfs_write_data *data, unsigned int count, int how)
};
/* Note: NFSv2 ignores @stable and always uses NFS_FILE_SYNC */
req
=
nfs_list_entry
(
data
->
pages
.
next
);
data
->
args
.
fh
=
NFS_FH
(
inode
);
data
->
args
.
offset
=
req_offset
(
req
);
data
->
args
.
pgbase
=
req
->
wb_pgbase
;
data
->
args
.
count
=
count
;
data
->
args
.
stable
=
NFS_FILE_SYNC
;
data
->
args
.
pages
=
data
->
pagevec
;
data
->
res
.
fattr
=
&
data
->
fattr
;
data
->
res
.
count
=
count
;
data
->
res
.
verf
=
&
data
->
verf
;
/* Set the initial flags for the task. */
flags
=
(
how
&
FLUSH_SYNC
)
?
0
:
RPC_TASK_ASYNC
;
/* Finalize the task. */
rpc_init_task
(
task
,
NFS_CLIENT
(
inode
),
nfs_write_done
,
flags
);
task
->
tk_calldata
=
data
;
/* Release requests */
task
->
tk_release
=
nfs_writedata_release
;
rpc_call_setup
(
&
data
->
task
,
&
msg
,
0
);
rpc_call_setup
(
task
,
&
msg
,
0
);
}
static
void
nfs_proc_commit_setup
(
struct
nfs_write_data
*
data
,
u64
start
,
u32
len
,
int
how
)
nfs_proc_commit_setup
(
struct
nfs_write_data
*
data
,
int
how
)
{
BUG
();
}
...
...
fs/nfs/write.c
View file @
b1355604
...
...
@@ -74,6 +74,8 @@
static
struct
nfs_page
*
nfs_update_request
(
struct
file
*
,
struct
inode
*
,
struct
page
*
,
unsigned
int
,
unsigned
int
);
static
void
nfs_writeback_done_partial
(
struct
nfs_write_data
*
,
int
);
static
void
nfs_writeback_done_full
(
struct
nfs_write_data
*
,
int
);
static
kmem_cache_t
*
nfs_wdata_cachep
;
static
mempool_t
*
nfs_wdata_mempool
;
...
...
@@ -95,7 +97,7 @@ static __inline__ void nfs_writedata_free(struct nfs_write_data *p)
mempool_free
(
p
,
nfs_wdata_mempool
);
}
void
nfs_writedata_release
(
struct
rpc_task
*
task
)
static
void
nfs_writedata_release
(
struct
rpc_task
*
task
)
{
struct
nfs_write_data
*
wdata
=
(
struct
nfs_write_data
*
)
task
->
tk_calldata
;
nfs_writedata_free
(
wdata
);
...
...
@@ -117,12 +119,6 @@ static __inline__ void nfs_commit_free(struct nfs_write_data *p)
mempool_free
(
p
,
nfs_commit_mempool
);
}
void
nfs_commit_release
(
struct
rpc_task
*
task
)
{
struct
nfs_write_data
*
wdata
=
(
struct
nfs_write_data
*
)
task
->
tk_calldata
;
nfs_commit_free
(
wdata
);
}
/* Adjust the file length if we're writing beyond the end */
static
void
nfs_grow_file
(
struct
page
*
page
,
unsigned
int
offset
,
unsigned
int
count
)
{
...
...
@@ -186,6 +182,7 @@ nfs_writepage_sync(struct file *file, struct inode *inode, struct page *page,
.
inode
=
inode
,
.
args
=
{
.
fh
=
NFS_FH
(
inode
),
.
lockowner
=
current
->
files
,
.
pages
=
&
page
,
.
stable
=
NFS_FILE_SYNC
,
.
pgbase
=
offset
,
...
...
@@ -299,8 +296,7 @@ nfs_writepage(struct page *page, struct writeback_control *wbc)
goto
out
;
do_it:
lock_kernel
();
if
(
NFS_SERVER
(
inode
)
->
wsize
>=
PAGE_CACHE_SIZE
&&
!
IS_SYNC
(
inode
)
&&
inode_referenced
)
{
if
(
!
IS_SYNC
(
inode
)
&&
inode_referenced
)
{
err
=
nfs_writepage_async
(
NULL
,
inode
,
page
,
0
,
offset
);
if
(
err
>=
0
)
err
=
0
;
...
...
@@ -365,7 +361,7 @@ nfs_inode_add_request(struct inode *inode, struct nfs_page *req)
/*
* Insert a write request into an inode
*/
static
inline
void
static
void
nfs_inode_remove_request
(
struct
nfs_page
*
req
)
{
struct
nfs_inode
*
nfsi
;
...
...
@@ -416,7 +412,7 @@ nfs_find_request(struct inode *inode, unsigned long index)
/*
* Add a request to the inode's dirty list.
*/
static
inline
void
static
void
nfs_mark_request_dirty
(
struct
nfs_page
*
req
)
{
struct
inode
*
inode
=
req
->
wb_inode
;
...
...
@@ -444,7 +440,7 @@ nfs_dirty_request(struct nfs_page *req)
/*
* Add a request to the inode's commit list.
*/
static
inline
void
static
void
nfs_mark_request_commit
(
struct
nfs_page
*
req
)
{
struct
inode
*
inode
=
req
->
wb_inode
;
...
...
@@ -680,11 +676,7 @@ nfs_updatepage(struct file *file, struct page *page, unsigned int offset, unsign
dentry
->
d_parent
->
d_name
.
name
,
dentry
->
d_name
.
name
,
count
,
(
long
long
)(
page_offset
(
page
)
+
offset
));
/*
* If wsize is smaller than page size, update and write
* page synchronously.
*/
if
(
NFS_SERVER
(
inode
)
->
wsize
<
PAGE_CACHE_SIZE
||
IS_SYNC
(
inode
))
{
if
(
IS_SYNC
(
inode
))
{
status
=
nfs_writepage_sync
(
file
,
inode
,
page
,
offset
,
count
);
if
(
status
>
0
)
{
if
(
offset
==
0
&&
status
==
PAGE_CACHE_SIZE
)
...
...
@@ -747,43 +739,149 @@ nfs_updatepage(struct file *file, struct page *page, unsigned int offset, unsign
return
status
;
}
static
void
nfs_writepage_release
(
struct
nfs_page
*
req
)
{
end_page_writeback
(
req
->
wb_page
);
#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
if
(
!
PageError
(
req
->
wb_page
))
{
if
(
NFS_NEED_RESCHED
(
req
))
{
nfs_mark_request_dirty
(
req
);
goto
out
;
}
else
if
(
NFS_NEED_COMMIT
(
req
))
{
nfs_mark_request_commit
(
req
);
goto
out
;
}
}
nfs_inode_remove_request
(
req
);
out:
nfs_clear_commit
(
req
);
nfs_clear_reschedule
(
req
);
#else
nfs_inode_remove_request
(
req
);
#endif
nfs_unlock_request
(
req
);
}
/*
* Set up the argument/result storage required for the RPC call.
*/
static
void
nfs_write_rpcsetup
(
struct
list_head
*
head
,
struct
nfs_write_data
*
data
,
int
how
)
static
void
nfs_write_rpcsetup
(
struct
nfs_page
*
req
,
struct
nfs_write_data
*
data
,
unsigned
int
count
,
unsigned
int
offset
,
int
how
)
{
struct
rpc_task
*
task
=
&
data
->
task
;
struct
inode
*
inode
;
struct
nfs_page
*
req
;
struct
page
**
pages
;
unsigned
int
count
;
/* Set up the RPC argument and reply structs
* NB: take care not to mess about with data->commit et al. */
pages
=
data
->
pagevec
;
count
=
0
;
while
(
!
list_empty
(
head
))
{
req
=
nfs_list_entry
(
head
->
next
);
nfs_list_remove_request
(
req
);
nfs_list_add_request
(
req
,
&
data
->
pages
);
SetPageWriteback
(
req
->
wb_page
);
*
pages
++
=
req
->
wb_page
;
count
+=
req
->
wb_bytes
;
}
req
=
nfs_list_entry
(
data
->
pages
.
next
);
data
->
req
=
req
;
data
->
inode
=
inode
=
req
->
wb_inode
;
data
->
cred
=
req
->
wb_cred
;
NFS_PROTO
(
inode
)
->
write_setup
(
data
,
count
,
how
);
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
->
res
.
fattr
=
&
data
->
fattr
;
data
->
res
.
count
=
count
;
data
->
res
.
verf
=
&
data
->
verf
;
NFS_PROTO
(
inode
)
->
write_setup
(
data
,
how
);
data
->
task
.
tk_calldata
=
data
;
/* Release requests */
data
->
task
.
tk_release
=
nfs_writedata_release
;
dprintk
(
"NFS: %4d initiated write call (req %s/%Ld, %u bytes @ offset %Lu)
\n
"
,
task
->
tk_pid
,
inode
->
i_sb
->
s_id
,
(
long
long
)
NFS_FILEID
(
inode
),
count
,
(
unsigned
long
long
)
req_offset
(
req
));
(
unsigned
long
long
)
data
->
args
.
offset
);
}
static
void
nfs_execute_write
(
struct
nfs_write_data
*
data
)
{
struct
rpc_clnt
*
clnt
=
NFS_CLIENT
(
data
->
inode
);
sigset_t
oldset
;
rpc_clnt_sigmask
(
clnt
,
&
oldset
);
lock_kernel
();
rpc_execute
(
&
data
->
task
);
unlock_kernel
();
rpc_clnt_sigunmask
(
clnt
,
&
oldset
);
}
/*
* Generate multiple small requests to write out a single
* contiguous dirty area on one page.
*/
static
int
nfs_flush_multi
(
struct
list_head
*
head
,
struct
inode
*
inode
,
int
how
)
{
struct
nfs_page
*
req
=
nfs_list_entry
(
head
->
next
);
struct
page
*
page
=
req
->
wb_page
;
struct
nfs_write_data
*
data
;
unsigned
int
wsize
=
NFS_SERVER
(
inode
)
->
wsize
;
unsigned
int
nbytes
,
offset
;
int
requests
=
0
;
LIST_HEAD
(
list
);
nfs_list_remove_request
(
req
);
nbytes
=
req
->
wb_bytes
;
for
(;;)
{
data
=
nfs_writedata_alloc
();
if
(
!
data
)
goto
out_bad
;
list_add
(
&
data
->
pages
,
&
list
);
requests
++
;
if
(
nbytes
<=
wsize
)
break
;
nbytes
-=
wsize
;
}
atomic_set
(
&
req
->
wb_complete
,
requests
);
ClearPageError
(
page
);
SetPageWriteback
(
page
);
offset
=
0
;
nbytes
=
req
->
wb_bytes
;
do
{
data
=
list_entry
(
list
.
next
,
struct
nfs_write_data
,
pages
);
list_del_init
(
&
data
->
pages
);
data
->
pagevec
[
0
]
=
page
;
data
->
complete
=
nfs_writeback_done_partial
;
if
(
nbytes
>
wsize
)
{
nfs_write_rpcsetup
(
req
,
data
,
wsize
,
offset
,
how
);
offset
+=
wsize
;
nbytes
-=
wsize
;
}
else
{
nfs_write_rpcsetup
(
req
,
data
,
nbytes
,
offset
,
how
);
nbytes
=
0
;
}
nfs_execute_write
(
data
);
}
while
(
nbytes
!=
0
);
return
0
;
out_bad:
while
(
!
list_empty
(
&
list
))
{
data
=
list_entry
(
list
.
next
,
struct
nfs_write_data
,
pages
);
list_del
(
&
data
->
pages
);
nfs_writedata_free
(
data
);
}
nfs_mark_request_dirty
(
req
);
nfs_unlock_request
(
req
);
return
-
ENOMEM
;
}
/*
...
...
@@ -794,25 +892,38 @@ nfs_write_rpcsetup(struct list_head *head, struct nfs_write_data *data, int how)
* This is the case if nfs_updatepage detects a conflicting request
* that has been written but not committed.
*/
static
int
nfs_flush_one
(
struct
list_head
*
head
,
struct
inode
*
inode
,
int
how
)
static
int
nfs_flush_one
(
struct
list_head
*
head
,
struct
inode
*
inode
,
int
how
)
{
struct
rpc_clnt
*
clnt
=
NFS_CLIENT
(
inode
);
struct
nfs_page
*
req
;
struct
page
**
pages
;
struct
nfs_write_data
*
data
;
sigset_t
oldset
;
unsigned
int
count
;
if
(
NFS_SERVER
(
inode
)
->
wsize
<
PAGE_CACHE_SIZE
)
return
nfs_flush_multi
(
head
,
inode
,
how
);
data
=
nfs_writedata_alloc
();
if
(
!
data
)
goto
out_bad
;
pages
=
data
->
pagevec
;
count
=
0
;
while
(
!
list_empty
(
head
))
{
req
=
nfs_list_entry
(
head
->
next
);
nfs_list_remove_request
(
req
);
nfs_list_add_request
(
req
,
&
data
->
pages
);
ClearPageError
(
req
->
wb_page
);
SetPageWriteback
(
req
->
wb_page
);
*
pages
++
=
req
->
wb_page
;
count
+=
req
->
wb_bytes
;
}
req
=
nfs_list_entry
(
data
->
pages
.
next
);
data
->
complete
=
nfs_writeback_done_full
;
/* Set up the argument struct */
nfs_write_rpcsetup
(
head
,
data
,
how
);
nfs_write_rpcsetup
(
req
,
data
,
count
,
0
,
how
);
rpc_clnt_sigmask
(
clnt
,
&
oldset
);
lock_kernel
();
rpc_execute
(
&
data
->
task
);
unlock_kernel
();
rpc_clnt_sigunmask
(
clnt
,
&
oldset
);
nfs_execute_write
(
data
);
return
0
;
out_bad:
while
(
!
list_empty
(
head
))
{
...
...
@@ -851,18 +962,107 @@ nfs_flush_list(struct list_head *head, int wpages, int how)
return
error
;
}
/*
* Handle a write reply that flushed part of a page.
*/
static
void
nfs_writeback_done_partial
(
struct
nfs_write_data
*
data
,
int
status
)
{
struct
nfs_page
*
req
=
data
->
req
;
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_bytes
,
(
long
long
)
req_offset
(
req
));
if
(
status
<
0
)
{
ClearPageUptodate
(
page
);
SetPageError
(
page
);
if
(
req
->
wb_file
)
req
->
wb_file
->
f_error
=
status
;
dprintk
(
", error = %d
\n
"
,
status
);
}
else
{
#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
if
(
data
->
verf
.
committed
<
NFS_FILE_SYNC
)
{
if
(
!
NFS_NEED_COMMIT
(
req
))
{
nfs_defer_commit
(
req
);
memcpy
(
&
req
->
wb_verf
,
&
data
->
verf
,
sizeof
(
req
->
wb_verf
));
dprintk
(
" defer commit
\n
"
);
}
else
if
(
memcmp
(
&
req
->
wb_verf
,
&
data
->
verf
,
sizeof
(
req
->
wb_verf
)))
{
nfs_defer_reschedule
(
req
);
dprintk
(
" server reboot detected
\n
"
);
}
}
else
#endif
dprintk
(
" OK
\n
"
);
}
if
(
atomic_dec_and_test
(
&
req
->
wb_complete
))
nfs_writepage_release
(
req
);
}
/*
* Handle a write reply that flushes a whole page.
*
* FIXME: There is an inherent race with invalidate_inode_pages and
* writebacks since the page->count is kept > 1 for as long
* as the page has a write request pending.
*/
static
void
nfs_writeback_done_full
(
struct
nfs_write_data
*
data
,
int
status
)
{
struct
nfs_page
*
req
;
struct
page
*
page
;
/* Update attributes as result of writeback. */
while
(
!
list_empty
(
&
data
->
pages
))
{
req
=
nfs_list_entry
(
data
->
pages
.
next
);
nfs_list_remove_request
(
req
);
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_bytes
,
(
long
long
)
req_offset
(
req
));
if
(
status
<
0
)
{
ClearPageUptodate
(
page
);
SetPageError
(
page
);
if
(
req
->
wb_file
)
req
->
wb_file
->
f_error
=
status
;
end_page_writeback
(
page
);
nfs_inode_remove_request
(
req
);
dprintk
(
", error = %d
\n
"
,
status
);
goto
next
;
}
end_page_writeback
(
page
);
#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
if
(
data
->
args
.
stable
!=
NFS_UNSTABLE
||
data
->
verf
.
committed
==
NFS_FILE_SYNC
)
{
nfs_inode_remove_request
(
req
);
dprintk
(
" OK
\n
"
);
goto
next
;
}
memcpy
(
&
req
->
wb_verf
,
&
data
->
verf
,
sizeof
(
req
->
wb_verf
));
nfs_mark_request_commit
(
req
);
dprintk
(
" marked for commit
\n
"
);
#else
nfs_inode_remove_request
(
req
);
#endif
next:
nfs_unlock_request
(
req
);
}
}
/*
* This function is called when the WRITE call is complete.
*/
void
nfs_writeback_done
(
struct
rpc_task
*
task
)
void
nfs_writeback_done
(
struct
rpc_task
*
task
)
{
struct
nfs_write_data
*
data
=
(
struct
nfs_write_data
*
)
task
->
tk_calldata
;
struct
nfs_writeargs
*
argp
=
&
data
->
args
;
struct
nfs_writeres
*
resp
=
&
data
->
res
;
struct
nfs_page
*
req
;
struct
page
*
page
;
dprintk
(
"NFS: %4d nfs_writeback_done (status %d)
\n
"
,
task
->
tk_pid
,
task
->
tk_status
);
...
...
@@ -904,53 +1104,22 @@ nfs_writeback_done(struct rpc_task *task)
/*
* Process the nfs_page list
*/
while
(
!
list_empty
(
&
data
->
pages
))
{
req
=
nfs_list_entry
(
data
->
pages
.
next
);
nfs_list_remove_request
(
req
);
page
=
req
->
wb_page
;
data
->
complete
(
data
,
task
->
tk_status
);
}
dprintk
(
"NFS: write (%s/%Ld %d@%Ld)"
,
req
->
wb_inode
->
i_sb
->
s_id
,
(
long
long
)
NFS_FILEID
(
req
->
wb_inode
),
req
->
wb_bytes
,
(
long
long
)
req_offset
(
req
));
if
(
task
->
tk_status
<
0
)
{
ClearPageUptodate
(
page
);
SetPageError
(
page
);
if
(
req
->
wb_file
)
req
->
wb_file
->
f_error
=
task
->
tk_status
;
end_page_writeback
(
page
);
nfs_inode_remove_request
(
req
);
dprintk
(
", error = %d
\n
"
,
task
->
tk_status
);
goto
next
;
}
end_page_writeback
(
page
);
#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
if
(
argp
->
stable
!=
NFS_UNSTABLE
||
data
->
verf
.
committed
==
NFS_FILE_SYNC
)
{
nfs_inode_remove_request
(
req
);
dprintk
(
" OK
\n
"
);
goto
next
;
}
memcpy
(
&
req
->
wb_verf
,
&
data
->
verf
,
sizeof
(
req
->
wb_verf
));
nfs_mark_request_commit
(
req
);
dprintk
(
" marked for commit
\n
"
);
#else
nfs_inode_remove_request
(
req
);
#endif
next:
nfs_unlock_request
(
req
);
}
static
void
nfs_commit_release
(
struct
rpc_task
*
task
)
{
struct
nfs_write_data
*
wdata
=
(
struct
nfs_write_data
*
)
task
->
tk_calldata
;
nfs_commit_free
(
wdata
);
}
#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
/*
* Set up the argument/result storage required for the RPC call.
*/
static
void
nfs_commit_rpcsetup
(
struct
list_head
*
head
,
struct
nfs_write_data
*
data
,
int
how
)
static
void
nfs_commit_rpcsetup
(
struct
list_head
*
head
,
struct
nfs_write_data
*
data
,
int
how
)
{
struct
rpc_task
*
task
=
&
data
->
task
;
struct
nfs_page
*
first
,
*
last
;
...
...
@@ -979,7 +1148,18 @@ nfs_commit_rpcsetup(struct list_head *head, struct nfs_write_data *data, int how
data
->
inode
=
inode
;
data
->
cred
=
first
->
wb_cred
;
NFS_PROTO
(
inode
)
->
commit_setup
(
data
,
start
,
len
,
how
);
data
->
args
.
fh
=
NFS_FH
(
data
->
inode
);
data
->
args
.
offset
=
start
;
data
->
args
.
count
=
len
;
data
->
res
.
count
=
len
;
data
->
res
.
fattr
=
&
data
->
fattr
;
data
->
res
.
verf
=
&
data
->
verf
;
NFS_PROTO
(
inode
)
->
commit_setup
(
data
,
how
);
data
->
task
.
tk_calldata
=
data
;
/* Release requests */
data
->
task
.
tk_release
=
nfs_commit_release
;
dprintk
(
"NFS: %4d initiated commit call
\n
"
,
task
->
tk_pid
);
}
...
...
@@ -990,10 +1170,8 @@ nfs_commit_rpcsetup(struct list_head *head, struct nfs_write_data *data, int how
int
nfs_commit_list
(
struct
list_head
*
head
,
int
how
)
{
struct
rpc_clnt
*
clnt
;
struct
nfs_write_data
*
data
;
struct
nfs_page
*
req
;
sigset_t
oldset
;
data
=
nfs_commit_alloc
();
...
...
@@ -1002,13 +1180,8 @@ nfs_commit_list(struct list_head *head, int how)
/* Set up the argument struct */
nfs_commit_rpcsetup
(
head
,
data
,
how
);
clnt
=
NFS_CLIENT
(
data
->
inode
);
rpc_clnt_sigmask
(
clnt
,
&
oldset
);
lock_kernel
();
rpc_execute
(
&
data
->
task
);
unlock_kernel
();
rpc_clnt_sigunmask
(
clnt
,
&
oldset
);
nfs_execute_write
(
data
);
return
0
;
out_bad:
while
(
!
list_empty
(
head
))
{
...
...
include/linux/nfs_fs.h
View file @
b1355604
...
...
@@ -335,10 +335,8 @@ extern int nfs_writepages(struct address_space *, struct writeback_control *);
extern
int
nfs_flush_incompatible
(
struct
file
*
file
,
struct
page
*
page
);
extern
int
nfs_updatepage
(
struct
file
*
,
struct
page
*
,
unsigned
int
,
unsigned
int
);
extern
void
nfs_writeback_done
(
struct
rpc_task
*
task
);
extern
void
nfs_writedata_release
(
struct
rpc_task
*
task
);
#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
extern
void
nfs_commit_release
(
struct
rpc_task
*
task
);
extern
void
nfs_commit_done
(
struct
rpc_task
*
);
#endif
...
...
include/linux/nfs_xdr.h
View file @
b1355604
...
...
@@ -253,7 +253,8 @@ struct nfs_readres {
struct
nfs_writeargs
{
struct
nfs_fh
*
fh
;
nfs4_stateid
stateid
;
fl_owner_t
lockowner
;
struct
nfs4_state
*
state
;
__u64
offset
;
__u32
count
;
enum
nfs3_stable_how
stable
;
...
...
@@ -681,7 +682,6 @@ struct nfs_write_data {
struct
rpc_task
task
;
struct
inode
*
inode
;
struct
rpc_cred
*
cred
;
fl_owner_t
lockowner
;
struct
nfs_fattr
fattr
;
struct
nfs_writeverf
verf
;
struct
list_head
pages
;
/* Coalesced requests we wish to flush */
...
...
@@ -742,8 +742,8 @@ struct nfs_rpc_ops {
struct
nfs_pathconf
*
);
u32
*
(
*
decode_dirent
)(
u32
*
,
struct
nfs_entry
*
,
int
plus
);
void
(
*
read_setup
)
(
struct
nfs_read_data
*
);
void
(
*
write_setup
)
(
struct
nfs_write_data
*
,
unsigned
int
count
,
int
how
);
void
(
*
commit_setup
)
(
struct
nfs_write_data
*
,
u64
start
,
u32
len
,
int
how
);
void
(
*
write_setup
)
(
struct
nfs_write_data
*
,
int
how
);
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
*
);
...
...
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