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
0acd2201
Commit
0acd2201
authored
Mar 24, 2011
by
Trond Myklebust
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'nfs-for-2.6.39' into nfs-for-next
parents
8f70e95f
35124a09
Changes
21
Hide whitespace changes
Inline
Side-by-side
Showing
21 changed files
with
1237 additions
and
193 deletions
+1237
-193
fs/nfs/dir.c
fs/nfs/dir.c
+75
-8
fs/nfs/file.c
fs/nfs/file.c
+3
-0
fs/nfs/getroot.c
fs/nfs/getroot.c
+4
-0
fs/nfs/inode.c
fs/nfs/inode.c
+1
-1
fs/nfs/internal.h
fs/nfs/internal.h
+14
-0
fs/nfs/nfs4_fs.h
fs/nfs/nfs4_fs.h
+2
-0
fs/nfs/nfs4filelayout.c
fs/nfs/nfs4filelayout.c
+329
-23
fs/nfs/nfs4filelayout.h
fs/nfs/nfs4filelayout.h
+2
-0
fs/nfs/nfs4filelayoutdev.c
fs/nfs/nfs4filelayoutdev.c
+122
-56
fs/nfs/nfs4proc.c
fs/nfs/nfs4proc.c
+111
-14
fs/nfs/nfs4xdr.c
fs/nfs/nfs4xdr.c
+154
-13
fs/nfs/pagelist.c
fs/nfs/pagelist.c
+6
-2
fs/nfs/pnfs.c
fs/nfs/pnfs.c
+142
-0
fs/nfs/pnfs.h
fs/nfs/pnfs.h
+81
-2
fs/nfs/write.c
fs/nfs/write.c
+144
-70
fs/nfs_common/nfsacl.c
fs/nfs_common/nfsacl.c
+0
-1
include/linux/nfs4.h
include/linux/nfs4.h
+1
-0
include/linux/nfs_fs.h
include/linux/nfs_fs.h
+10
-0
include/linux/nfs_page.h
include/linux/nfs_page.h
+6
-1
include/linux/nfs_xdr.h
include/linux/nfs_xdr.h
+28
-2
net/sunrpc/xprtsock.c
net/sunrpc/xprtsock.c
+2
-0
No files found.
fs/nfs/dir.c
View file @
0acd2201
...
...
@@ -44,6 +44,7 @@
/* #define NFS_DEBUG_VERBOSE 1 */
static
int
nfs_opendir
(
struct
inode
*
,
struct
file
*
);
static
int
nfs_closedir
(
struct
inode
*
,
struct
file
*
);
static
int
nfs_readdir
(
struct
file
*
,
void
*
,
filldir_t
);
static
struct
dentry
*
nfs_lookup
(
struct
inode
*
,
struct
dentry
*
,
struct
nameidata
*
);
static
int
nfs_create
(
struct
inode
*
,
struct
dentry
*
,
int
,
struct
nameidata
*
);
...
...
@@ -64,7 +65,7 @@ const struct file_operations nfs_dir_operations = {
.
read
=
generic_read_dir
,
.
readdir
=
nfs_readdir
,
.
open
=
nfs_opendir
,
.
release
=
nfs_
release
,
.
release
=
nfs_
closedir
,
.
fsync
=
nfs_fsync_dir
,
};
...
...
@@ -133,13 +134,35 @@ const struct inode_operations nfs4_dir_inode_operations = {
#endif
/* CONFIG_NFS_V4 */
static
struct
nfs_open_dir_context
*
alloc_nfs_open_dir_context
(
struct
rpc_cred
*
cred
)
{
struct
nfs_open_dir_context
*
ctx
;
ctx
=
kmalloc
(
sizeof
(
*
ctx
),
GFP_KERNEL
);
if
(
ctx
!=
NULL
)
{
ctx
->
duped
=
0
;
ctx
->
dir_cookie
=
0
;
ctx
->
dup_cookie
=
0
;
ctx
->
cred
=
get_rpccred
(
cred
);
}
else
ctx
=
ERR_PTR
(
-
ENOMEM
);
return
ctx
;
}
static
void
put_nfs_open_dir_context
(
struct
nfs_open_dir_context
*
ctx
)
{
put_rpccred
(
ctx
->
cred
);
kfree
(
ctx
);
}
/*
* Open file
*/
static
int
nfs_opendir
(
struct
inode
*
inode
,
struct
file
*
filp
)
{
int
res
;
int
res
=
0
;
struct
nfs_open_dir_context
*
ctx
;
struct
rpc_cred
*
cred
;
dfprintk
(
FILE
,
"NFS: open dir(%s/%s)
\n
"
,
filp
->
f_path
.
dentry
->
d_parent
->
d_name
.
name
,
...
...
@@ -147,8 +170,15 @@ nfs_opendir(struct inode *inode, struct file *filp)
nfs_inc_stats
(
inode
,
NFSIOS_VFSOPEN
);
/* Call generic open code in order to cache credentials */
res
=
nfs_open
(
inode
,
filp
);
cred
=
rpc_lookup_cred
();
if
(
IS_ERR
(
cred
))
return
PTR_ERR
(
cred
);
ctx
=
alloc_nfs_open_dir_context
(
cred
);
if
(
IS_ERR
(
ctx
))
{
res
=
PTR_ERR
(
ctx
);
goto
out
;
}
filp
->
private_data
=
ctx
;
if
(
filp
->
f_path
.
dentry
==
filp
->
f_path
.
mnt
->
mnt_root
)
{
/* This is a mountpoint, so d_revalidate will never
* have been called, so we need to refresh the
...
...
@@ -156,9 +186,18 @@ nfs_opendir(struct inode *inode, struct file *filp)
*/
__nfs_revalidate_inode
(
NFS_SERVER
(
inode
),
inode
);
}
out:
put_rpccred
(
cred
);
return
res
;
}
static
int
nfs_closedir
(
struct
inode
*
inode
,
struct
file
*
filp
)
{
put_nfs_open_dir_context
(
filp
->
private_data
);
return
0
;
}
struct
nfs_cache_array_entry
{
u64
cookie
;
u64
ino
;
...
...
@@ -284,19 +323,20 @@ int nfs_readdir_search_for_pos(struct nfs_cache_array *array, nfs_readdir_descri
{
loff_t
diff
=
desc
->
file
->
f_pos
-
desc
->
current_index
;
unsigned
int
index
;
struct
nfs_open_dir_context
*
ctx
=
desc
->
file
->
private_data
;
if
(
diff
<
0
)
goto
out_eof
;
if
(
diff
>=
array
->
size
)
{
if
(
array
->
eof_index
>=
0
)
goto
out_eof
;
desc
->
current_index
+=
array
->
size
;
return
-
EAGAIN
;
}
index
=
(
unsigned
int
)
diff
;
*
desc
->
dir_cookie
=
array
->
array
[
index
].
cookie
;
desc
->
cache_entry_index
=
index
;
ctx
->
duped
=
0
;
return
0
;
out_eof:
desc
->
eof
=
1
;
...
...
@@ -307,10 +347,18 @@ static
int
nfs_readdir_search_for_cookie
(
struct
nfs_cache_array
*
array
,
nfs_readdir_descriptor_t
*
desc
)
{
int
i
;
loff_t
new_pos
;
int
status
=
-
EAGAIN
;
struct
nfs_open_dir_context
*
ctx
=
desc
->
file
->
private_data
;
for
(
i
=
0
;
i
<
array
->
size
;
i
++
)
{
if
(
array
->
array
[
i
].
cookie
==
*
desc
->
dir_cookie
)
{
new_pos
=
desc
->
current_index
+
i
;
if
(
new_pos
<
desc
->
file
->
f_pos
)
{
ctx
->
dup_cookie
=
*
desc
->
dir_cookie
;
ctx
->
duped
=
1
;
}
desc
->
file
->
f_pos
=
new_pos
;
desc
->
cache_entry_index
=
i
;
return
0
;
}
...
...
@@ -342,6 +390,7 @@ int nfs_readdir_search_array(nfs_readdir_descriptor_t *desc)
if
(
status
==
-
EAGAIN
)
{
desc
->
last_cookie
=
array
->
last_cookie
;
desc
->
current_index
+=
array
->
size
;
desc
->
page_index
++
;
}
nfs_readdir_release_array
(
desc
->
page
);
...
...
@@ -354,7 +403,8 @@ static
int
nfs_readdir_xdr_filler
(
struct
page
**
pages
,
nfs_readdir_descriptor_t
*
desc
,
struct
nfs_entry
*
entry
,
struct
file
*
file
,
struct
inode
*
inode
)
{
struct
rpc_cred
*
cred
=
nfs_file_cred
(
file
);
struct
nfs_open_dir_context
*
ctx
=
file
->
private_data
;
struct
rpc_cred
*
cred
=
ctx
->
cred
;
unsigned
long
timestamp
,
gencount
;
int
error
;
...
...
@@ -693,6 +743,20 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent,
int
i
=
0
;
int
res
=
0
;
struct
nfs_cache_array
*
array
=
NULL
;
struct
nfs_open_dir_context
*
ctx
=
file
->
private_data
;
if
(
ctx
->
duped
!=
0
&&
ctx
->
dup_cookie
==
*
desc
->
dir_cookie
)
{
if
(
printk_ratelimit
())
{
pr_notice
(
"NFS: directory %s/%s contains a readdir loop. "
"Please contact your server vendor. "
"Offending cookie: %llu
\n
"
,
file
->
f_dentry
->
d_parent
->
d_name
.
name
,
file
->
f_dentry
->
d_name
.
name
,
*
desc
->
dir_cookie
);
}
res
=
-
ELOOP
;
goto
out
;
}
array
=
nfs_readdir_get_array
(
desc
->
page
);
if
(
IS_ERR
(
array
))
{
...
...
@@ -785,6 +849,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
struct
inode
*
inode
=
dentry
->
d_inode
;
nfs_readdir_descriptor_t
my_desc
,
*
desc
=
&
my_desc
;
struct
nfs_open_dir_context
*
dir_ctx
=
filp
->
private_data
;
int
res
;
dfprintk
(
FILE
,
"NFS: readdir(%s/%s) starting at cookie %llu
\n
"
,
...
...
@@ -801,7 +866,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
memset
(
desc
,
0
,
sizeof
(
*
desc
));
desc
->
file
=
filp
;
desc
->
dir_cookie
=
&
nfs_file_open_context
(
filp
)
->
dir_cookie
;
desc
->
dir_cookie
=
&
dir_ctx
->
dir_cookie
;
desc
->
decode
=
NFS_PROTO
(
inode
)
->
decode_dirent
;
desc
->
plus
=
NFS_USE_READDIRPLUS
(
inode
);
...
...
@@ -853,6 +918,7 @@ static loff_t nfs_llseek_dir(struct file *filp, loff_t offset, int origin)
{
struct
dentry
*
dentry
=
filp
->
f_path
.
dentry
;
struct
inode
*
inode
=
dentry
->
d_inode
;
struct
nfs_open_dir_context
*
dir_ctx
=
filp
->
private_data
;
dfprintk
(
FILE
,
"NFS: llseek dir(%s/%s, %lld, %d)
\n
"
,
dentry
->
d_parent
->
d_name
.
name
,
...
...
@@ -872,7 +938,8 @@ static loff_t nfs_llseek_dir(struct file *filp, loff_t offset, int origin)
}
if
(
offset
!=
filp
->
f_pos
)
{
filp
->
f_pos
=
offset
;
nfs_file_open_context
(
filp
)
->
dir_cookie
=
0
;
dir_ctx
->
dir_cookie
=
0
;
dir_ctx
->
duped
=
0
;
}
out:
mutex_unlock
(
&
inode
->
i_mutex
);
...
...
fs/nfs/file.c
View file @
0acd2201
...
...
@@ -326,6 +326,9 @@ nfs_file_fsync(struct file *file, int datasync)
ret
=
xchg
(
&
ctx
->
error
,
0
);
if
(
!
ret
&&
status
<
0
)
ret
=
status
;
if
(
!
ret
&&
!
datasync
)
/* application has asked for meta-data sync */
ret
=
pnfs_layoutcommit_inode
(
inode
,
true
);
return
ret
;
}
...
...
fs/nfs/getroot.c
View file @
0acd2201
...
...
@@ -222,6 +222,10 @@ struct dentry *nfs4_get_root(struct super_block *sb, struct nfs_fh *mntfh,
goto
out
;
}
if
(
fattr
->
valid
&
NFS_ATTR_FATTR_FSID
&&
!
nfs_fsid_equal
(
&
server
->
fsid
,
&
fattr
->
fsid
))
memcpy
(
&
server
->
fsid
,
&
fattr
->
fsid
,
sizeof
(
server
->
fsid
));
inode
=
nfs_fhget
(
sb
,
mntfh
,
fattr
);
if
(
IS_ERR
(
inode
))
{
dprintk
(
"nfs_get_root: get root inode failed
\n
"
);
...
...
fs/nfs/inode.c
View file @
0acd2201
...
...
@@ -641,7 +641,6 @@ struct nfs_open_context *alloc_nfs_open_context(struct path *path, struct rpc_cr
ctx
->
mode
=
f_mode
;
ctx
->
flags
=
0
;
ctx
->
error
=
0
;
ctx
->
dir_cookie
=
0
;
nfs_init_lock_context
(
&
ctx
->
lock_context
);
ctx
->
lock_context
.
open_context
=
ctx
;
INIT_LIST_HEAD
(
&
ctx
->
list
);
...
...
@@ -1473,6 +1472,7 @@ static inline void nfs4_init_once(struct nfs_inode *nfsi)
nfsi
->
delegation_state
=
0
;
init_rwsem
(
&
nfsi
->
rwsem
);
nfsi
->
layout
=
NULL
;
atomic_set
(
&
nfsi
->
commits_outstanding
,
0
);
#endif
}
...
...
fs/nfs/internal.h
View file @
0acd2201
...
...
@@ -283,11 +283,25 @@ extern int nfs_initiate_read(struct nfs_read_data *data, struct rpc_clnt *clnt,
extern
void
nfs_read_prepare
(
struct
rpc_task
*
task
,
void
*
calldata
);
/* write.c */
extern
void
nfs_commit_free
(
struct
nfs_write_data
*
p
);
extern
int
nfs_initiate_write
(
struct
nfs_write_data
*
data
,
struct
rpc_clnt
*
clnt
,
const
struct
rpc_call_ops
*
call_ops
,
int
how
);
extern
void
nfs_write_prepare
(
struct
rpc_task
*
task
,
void
*
calldata
);
extern
int
nfs_initiate_commit
(
struct
nfs_write_data
*
data
,
struct
rpc_clnt
*
clnt
,
const
struct
rpc_call_ops
*
call_ops
,
int
how
);
extern
void
nfs_init_commit
(
struct
nfs_write_data
*
data
,
struct
list_head
*
head
,
struct
pnfs_layout_segment
*
lseg
);
void
nfs_retry_commit
(
struct
list_head
*
page_list
,
struct
pnfs_layout_segment
*
lseg
);
void
nfs_commit_clear_lock
(
struct
nfs_inode
*
nfsi
);
void
nfs_commitdata_release
(
void
*
data
);
void
nfs_commit_release_pages
(
struct
nfs_write_data
*
data
);
#ifdef CONFIG_MIGRATION
extern
int
nfs_migrate_page
(
struct
address_space
*
,
struct
page
*
,
struct
page
*
);
...
...
fs/nfs/nfs4_fs.h
View file @
0acd2201
...
...
@@ -263,6 +263,8 @@ extern int nfs4_proc_destroy_session(struct nfs4_session *);
extern
int
nfs4_init_session
(
struct
nfs_server
*
server
);
extern
int
nfs4_proc_get_lease_time
(
struct
nfs_client
*
clp
,
struct
nfs_fsinfo
*
fsinfo
);
extern
int
nfs4_proc_layoutcommit
(
struct
nfs4_layoutcommit_data
*
data
,
bool
sync
);
static
inline
bool
is_ds_only_client
(
struct
nfs_client
*
clp
)
...
...
fs/nfs/nfs4filelayout.c
View file @
0acd2201
...
...
@@ -153,6 +153,23 @@ static int filelayout_read_done_cb(struct rpc_task *task,
return
0
;
}
/*
* We reference the rpc_cred of the first WRITE that triggers the need for
* a LAYOUTCOMMIT, and use it to send the layoutcommit compound.
* rfc5661 is not clear about which credential should be used.
*/
static
void
filelayout_set_layoutcommit
(
struct
nfs_write_data
*
wdata
)
{
if
(
FILELAYOUT_LSEG
(
wdata
->
lseg
)
->
commit_through_mds
||
wdata
->
res
.
verf
->
committed
==
NFS_FILE_SYNC
)
return
;
pnfs_set_layoutcommit
(
wdata
);
dprintk
(
"%s ionde %lu pls_end_pos %lu
\n
"
,
__func__
,
wdata
->
inode
->
i_ino
,
(
unsigned
long
)
wdata
->
lseg
->
pls_end_pos
);
}
/*
* Call ops for the async read/write cases
* In the case of dense layouts, the offset needs to be reset to its
...
...
@@ -210,6 +227,38 @@ static int filelayout_write_done_cb(struct rpc_task *task,
return
-
EAGAIN
;
}
filelayout_set_layoutcommit
(
data
);
return
0
;
}
/* Fake up some data that will cause nfs_commit_release to retry the writes. */
static
void
prepare_to_resend_writes
(
struct
nfs_write_data
*
data
)
{
struct
nfs_page
*
first
=
nfs_list_entry
(
data
->
pages
.
next
);
data
->
task
.
tk_status
=
0
;
memcpy
(
data
->
verf
.
verifier
,
first
->
wb_verf
.
verifier
,
sizeof
(
first
->
wb_verf
.
verifier
));
data
->
verf
.
verifier
[
0
]
++
;
/* ensure verifier mismatch */
}
static
int
filelayout_commit_done_cb
(
struct
rpc_task
*
task
,
struct
nfs_write_data
*
data
)
{
int
reset
=
0
;
if
(
filelayout_async_handle_error
(
task
,
data
->
args
.
context
->
state
,
data
->
ds_clp
,
&
reset
)
==
-
EAGAIN
)
{
dprintk
(
"%s calling restart ds_clp %p ds_clp->cl_session %p
\n
"
,
__func__
,
data
->
ds_clp
,
data
->
ds_clp
->
cl_session
);
if
(
reset
)
{
prepare_to_resend_writes
(
data
);
filelayout_set_lo_fail
(
data
->
lseg
);
}
else
nfs_restart_rpc
(
task
,
data
->
ds_clp
);
return
-
EAGAIN
;
}
return
0
;
}
...
...
@@ -240,6 +289,16 @@ static void filelayout_write_release(void *data)
wdata
->
mds_ops
->
rpc_release
(
data
);
}
static
void
filelayout_commit_release
(
void
*
data
)
{
struct
nfs_write_data
*
wdata
=
(
struct
nfs_write_data
*
)
data
;
nfs_commit_release_pages
(
wdata
);
if
(
atomic_dec_and_test
(
&
NFS_I
(
wdata
->
inode
)
->
commits_outstanding
))
nfs_commit_clear_lock
(
NFS_I
(
wdata
->
inode
));
nfs_commitdata_release
(
wdata
);
}
struct
rpc_call_ops
filelayout_read_call_ops
=
{
.
rpc_call_prepare
=
filelayout_read_prepare
,
.
rpc_call_done
=
filelayout_read_call_done
,
...
...
@@ -252,6 +311,12 @@ struct rpc_call_ops filelayout_write_call_ops = {
.
rpc_release
=
filelayout_write_release
,
};
struct
rpc_call_ops
filelayout_commit_call_ops
=
{
.
rpc_call_prepare
=
filelayout_write_prepare
,
.
rpc_call_done
=
filelayout_write_call_done
,
.
rpc_release
=
filelayout_commit_release
,
};
static
enum
pnfs_try_status
filelayout_read_pagelist
(
struct
nfs_read_data
*
data
)
{
...
...
@@ -320,10 +385,6 @@ filelayout_write_pagelist(struct nfs_write_data *data, int sync)
data
->
inode
->
i_ino
,
sync
,
(
size_t
)
data
->
args
.
count
,
offset
,
ntohl
(
ds
->
ds_ip_addr
),
ntohs
(
ds
->
ds_port
));
/* We can't handle commit to ds yet */
if
(
!
FILELAYOUT_LSEG
(
lseg
)
->
commit_through_mds
)
data
->
args
.
stable
=
NFS_FILE_SYNC
;
data
->
write_done_cb
=
filelayout_write_done_cb
;
data
->
ds_clp
=
ds
->
ds_clp
;
fh
=
nfs4_fl_select_ds_fh
(
lseg
,
j
);
...
...
@@ -441,12 +502,33 @@ filelayout_decode_layout(struct pnfs_layout_hdr *flo,
struct
nfs4_layoutget_res
*
lgr
,
struct
nfs4_deviceid
*
id
)
{
uint32_t
*
p
=
(
uint32_t
*
)
lgr
->
layout
.
buf
;
struct
xdr_stream
stream
;
struct
xdr_buf
buf
=
{
.
pages
=
lgr
->
layoutp
->
pages
,
.
page_len
=
lgr
->
layoutp
->
len
,
.
buflen
=
lgr
->
layoutp
->
len
,
.
len
=
lgr
->
layoutp
->
len
,
};
struct
page
*
scratch
;
__be32
*
p
;
uint32_t
nfl_util
;
int
i
;
dprintk
(
"%s: set_layout_map Begin
\n
"
,
__func__
);
scratch
=
alloc_page
(
GFP_KERNEL
);
if
(
!
scratch
)
return
-
ENOMEM
;
xdr_init_decode
(
&
stream
,
&
buf
,
NULL
);
xdr_set_scratch_buffer
(
&
stream
,
page_address
(
scratch
),
PAGE_SIZE
);
/* 20 = ufl_util (4), first_stripe_index (4), pattern_offset (8),
* num_fh (4) */
p
=
xdr_inline_decode
(
&
stream
,
NFS4_DEVICEID4_SIZE
+
20
);
if
(
unlikely
(
!
p
))
goto
out_err
;
memcpy
(
id
,
p
,
sizeof
(
*
id
));
p
+=
XDR_QUADLEN
(
NFS4_DEVICEID4_SIZE
);
print_deviceid
(
id
);
...
...
@@ -468,32 +550,57 @@ filelayout_decode_layout(struct pnfs_layout_hdr *flo,
__func__
,
nfl_util
,
fl
->
num_fh
,
fl
->
first_stripe_index
,
fl
->
pattern_offset
);
if
(
!
fl
->
num_fh
)
goto
out_err
;
fl
->
fh_array
=
kzalloc
(
fl
->
num_fh
*
sizeof
(
struct
nfs_fh
*
),
GFP_KERNEL
);
if
(
!
fl
->
fh_array
)
return
-
ENOMEM
;
goto
out_err
;
for
(
i
=
0
;
i
<
fl
->
num_fh
;
i
++
)
{
/* Do we want to use a mempool here? */
fl
->
fh_array
[
i
]
=
kmalloc
(
sizeof
(
struct
nfs_fh
),
GFP_KERNEL
);
if
(
!
fl
->
fh_array
[
i
])
{
filelayout_free_fh_array
(
fl
);
return
-
ENOMEM
;
}
if
(
!
fl
->
fh_array
[
i
])
goto
out_err_free
;
p
=
xdr_inline_decode
(
&
stream
,
4
);
if
(
unlikely
(
!
p
))
goto
out_err_free
;
fl
->
fh_array
[
i
]
->
size
=
be32_to_cpup
(
p
++
);
if
(
sizeof
(
struct
nfs_fh
)
<
fl
->
fh_array
[
i
]
->
size
)
{
printk
(
KERN_ERR
"Too big fh %d received %d
\n
"
,
i
,
fl
->
fh_array
[
i
]
->
size
);
filelayout_free_fh_array
(
fl
);
return
-
EIO
;
goto
out_err_free
;
}
p
=
xdr_inline_decode
(
&
stream
,
fl
->
fh_array
[
i
]
->
size
);
if
(
unlikely
(
!
p
))
goto
out_err_free
;
memcpy
(
fl
->
fh_array
[
i
]
->
data
,
p
,
fl
->
fh_array
[
i
]
->
size
);
p
+=
XDR_QUADLEN
(
fl
->
fh_array
[
i
]
->
size
);
dprintk
(
"DEBUG: %s: fh len %d
\n
"
,
__func__
,
fl
->
fh_array
[
i
]
->
size
);
}
__free_page
(
scratch
);
return
0
;
out_err_free:
filelayout_free_fh_array
(
fl
);
out_err:
__free_page
(
scratch
);
return
-
EIO
;
}
static
void
filelayout_free_lseg
(
struct
pnfs_layout_segment
*
lseg
)
{
struct
nfs4_filelayout_segment
*
fl
=
FILELAYOUT_LSEG
(
lseg
);
dprintk
(
"--> %s
\n
"
,
__func__
);
nfs4_fl_put_deviceid
(
fl
->
dsaddr
);
kfree
(
fl
->
commit_buckets
);
_filelayout_free_lseg
(
fl
);
}
static
struct
pnfs_layout_segment
*
...
...
@@ -514,17 +621,28 @@ filelayout_alloc_lseg(struct pnfs_layout_hdr *layoutid,
_filelayout_free_lseg
(
fl
);
return
NULL
;
}
return
&
fl
->
generic_hdr
;
}
static
void
filelayout_free_lseg
(
struct
pnfs_layout_segment
*
lseg
)
{
struct
nfs4_filelayout_segment
*
fl
=
FILELAYOUT_LSEG
(
lseg
);
dprintk
(
"--> %s
\n
"
,
__func__
);
nfs4_fl_put_deviceid
(
fl
->
dsaddr
);
_filelayout_free_lseg
(
fl
);
/* This assumes there is only one IOMODE_RW lseg. What
* we really want to do is have a layout_hdr level
* dictionary of <multipath_list4, fh> keys, each
* associated with a struct list_head, populated by calls
* to filelayout_write_pagelist().
* */
if
((
!
fl
->
commit_through_mds
)
&&
(
lgr
->
range
.
iomode
==
IOMODE_RW
))
{
int
i
;
int
size
=
(
fl
->
stripe_type
==
STRIPE_SPARSE
)
?
fl
->
dsaddr
->
ds_num
:
fl
->
dsaddr
->
stripe_count
;
fl
->
commit_buckets
=
kcalloc
(
size
,
sizeof
(
struct
list_head
),
GFP_KERNEL
);
if
(
!
fl
->
commit_buckets
)
{
filelayout_free_lseg
(
&
fl
->
generic_hdr
);
return
NULL
;
}
fl
->
number_of_buckets
=
size
;
for
(
i
=
0
;
i
<
size
;
i
++
)
INIT_LIST_HEAD
(
&
fl
->
commit_buckets
[
i
]);
}
return
&
fl
->
generic_hdr
;
}
/*
...
...
@@ -552,6 +670,191 @@ filelayout_pg_test(struct nfs_pageio_descriptor *pgio, struct nfs_page *prev,
return
(
p_stripe
==
r_stripe
);
}
static
bool
filelayout_mark_pnfs_commit
(
struct
pnfs_layout_segment
*
lseg
)
{
return
!
FILELAYOUT_LSEG
(
lseg
)
->
commit_through_mds
;
}
static
u32
select_bucket_index
(
struct
nfs4_filelayout_segment
*
fl
,
u32
j
)
{
if
(
fl
->
stripe_type
==
STRIPE_SPARSE
)
return
nfs4_fl_calc_ds_index
(
&
fl
->
generic_hdr
,
j
);
else
return
j
;
}
struct
list_head
*
filelayout_choose_commit_list
(
struct
nfs_page
*
req
)
{
struct
pnfs_layout_segment
*
lseg
=
req
->
wb_commit_lseg
;
struct
nfs4_filelayout_segment
*
fl
=
FILELAYOUT_LSEG
(
lseg
);
u32
i
,
j
;
struct
list_head
*
list
;
/* Note that we are calling nfs4_fl_calc_j_index on each page
* that ends up being committed to a data server. An attractive
* alternative is to add a field to nfs_write_data and nfs_page
* to store the value calculated in filelayout_write_pagelist
* and just use that here.
*/
j
=
nfs4_fl_calc_j_index
(
lseg
,
(
loff_t
)
req
->
wb_index
<<
PAGE_CACHE_SHIFT
);
i
=
select_bucket_index
(
fl
,
j
);
list
=
&
fl
->
commit_buckets
[
i
];
if
(
list_empty
(
list
))
{
/* Non-empty buckets hold a reference on the lseg */
get_lseg
(
lseg
);
}
return
list
;
}
static
u32
calc_ds_index_from_commit
(
struct
pnfs_layout_segment
*
lseg
,
u32
i
)
{
struct
nfs4_filelayout_segment
*
flseg
=
FILELAYOUT_LSEG
(
lseg
);
if
(
flseg
->
stripe_type
==
STRIPE_SPARSE
)
return
i
;
else
return
nfs4_fl_calc_ds_index
(
lseg
,
i
);
}
static
struct
nfs_fh
*
select_ds_fh_from_commit
(
struct
pnfs_layout_segment
*
lseg
,
u32
i
)
{
struct
nfs4_filelayout_segment
*
flseg
=
FILELAYOUT_LSEG
(
lseg
);
if
(
flseg
->
stripe_type
==
STRIPE_SPARSE
)
{
if
(
flseg
->
num_fh
==
1
)
i
=
0
;
else
if
(
flseg
->
num_fh
==
0
)
/* Use the MDS OPEN fh set in nfs_read_rpcsetup */
return
NULL
;
}
return
flseg
->
fh_array
[
i
];
}
static
int
filelayout_initiate_commit
(
struct
nfs_write_data
*
data
,
int
how
)
{
struct
pnfs_layout_segment
*
lseg
=
data
->
lseg
;
struct
nfs4_pnfs_ds
*
ds
;
u32
idx
;
struct
nfs_fh
*
fh
;
idx
=
calc_ds_index_from_commit
(
lseg
,
data
->
ds_commit_index
);
ds
=
nfs4_fl_prepare_ds
(
lseg
,
idx
);
if
(
!
ds
)
{
printk
(
KERN_ERR
"%s: prepare_ds failed, use MDS
\n
"
,
__func__
);
set_bit
(
lo_fail_bit
(
IOMODE_RW
),
&
lseg
->
pls_layout
->
plh_flags
);
set_bit
(
lo_fail_bit
(
IOMODE_READ
),
&
lseg
->
pls_layout
->
plh_flags
);
prepare_to_resend_writes
(
data
);
data
->
mds_ops
->
rpc_release
(
data
);
return
-
EAGAIN
;
}
dprintk
(
"%s ino %lu, how %d
\n
"
,
__func__
,
data
->
inode
->
i_ino
,
how
);
data
->
write_done_cb
=
filelayout_commit_done_cb
;
data
->
ds_clp
=
ds
->
ds_clp
;
fh
=
select_ds_fh_from_commit
(
lseg
,
data
->
ds_commit_index
);
if
(
fh
)
data
->
args
.
fh
=
fh
;
return
nfs_initiate_commit
(
data
,
ds
->
ds_clp
->
cl_rpcclient
,
&
filelayout_commit_call_ops
,
how
);
}
/*
* This is only useful while we are using whole file layouts.
*/
static
struct
pnfs_layout_segment
*
find_only_write_lseg
(
struct
inode
*
inode
)
{
struct
pnfs_layout_segment
*
lseg
,
*
rv
=
NULL
;
spin_lock
(
&
inode
->
i_lock
);
list_for_each_entry
(
lseg
,
&
NFS_I
(
inode
)
->
layout
->
plh_segs
,
pls_list
)
if
(
lseg
->
pls_range
.
iomode
==
IOMODE_RW
)
rv
=
get_lseg
(
lseg
);
spin_unlock
(
&
inode
->
i_lock
);
return
rv
;
}
static
int
alloc_ds_commits
(
struct
inode
*
inode
,
struct
list_head
*
list
)
{
struct
pnfs_layout_segment
*
lseg
;
struct
nfs4_filelayout_segment
*
fl
;
struct
nfs_write_data
*
data
;
int
i
,
j
;
/* Won't need this when non-whole file layout segments are supported
* instead we will use a pnfs_layout_hdr structure */
lseg
=
find_only_write_lseg
(
inode
);
if
(
!
lseg
)
return
0
;
fl
=
FILELAYOUT_LSEG
(
lseg
);
for
(
i
=
0
;
i
<
fl
->
number_of_buckets
;
i
++
)
{
if
(
list_empty
(
&
fl
->
commit_buckets
[
i
]))
continue
;
data
=
nfs_commitdata_alloc
();
if
(
!
data
)
goto
out_bad
;
data
->
ds_commit_index
=
i
;
data
->
lseg
=
lseg
;
list_add
(
&
data
->
pages
,
list
);
}
put_lseg
(
lseg
);
return
0
;
out_bad:
for
(
j
=
i
;
j
<
fl
->
number_of_buckets
;
j
++
)
{
if
(
list_empty
(
&
fl
->
commit_buckets
[
i
]))
continue
;
nfs_retry_commit
(
&
fl
->
commit_buckets
[
i
],
lseg
);
put_lseg
(
lseg
);
/* associated with emptying bucket */
}
put_lseg
(
lseg
);
/* Caller will clean up entries put on list */
return
-
ENOMEM
;
}
/* This follows nfs_commit_list pretty closely */
static
int
filelayout_commit_pagelist
(
struct
inode
*
inode
,
struct
list_head
*
mds_pages
,
int
how
)
{
struct
nfs_write_data
*
data
,
*
tmp
;
LIST_HEAD
(
list
);
if
(
!
list_empty
(
mds_pages
))
{
data
=
nfs_commitdata_alloc
();
if
(
!
data
)
goto
out_bad
;
data
->
lseg
=
NULL
;
list_add
(
&
data
->
pages
,
&
list
);
}
if
(
alloc_ds_commits
(
inode
,
&
list
))
goto
out_bad
;
list_for_each_entry_safe
(
data
,
tmp
,
&
list
,
pages
)
{
list_del_init
(
&
data
->
pages
);
atomic_inc
(
&
NFS_I
(
inode
)
->
commits_outstanding
);
if
(
!
data
->
lseg
)
{
nfs_init_commit
(
data
,
mds_pages
,
NULL
);
nfs_initiate_commit
(
data
,
NFS_CLIENT
(
inode
),
data
->
mds_ops
,
how
);
}
else
{
nfs_init_commit
(
data
,
&
FILELAYOUT_LSEG
(
data
->
lseg
)
->
commit_buckets
[
data
->
ds_commit_index
],
data
->
lseg
);
filelayout_initiate_commit
(
data
,
how
);
}
}
return
0
;
out_bad:
list_for_each_entry_safe
(
data
,
tmp
,
&
list
,
pages
)
{
nfs_retry_commit
(
&
data
->
pages
,
data
->
lseg
);
list_del_init
(
&
data
->
pages
);
nfs_commit_free
(
data
);
}
nfs_retry_commit
(
mds_pages
,
NULL
);
nfs_commit_clear_lock
(
NFS_I
(
inode
));
return
-
ENOMEM
;
}
static
struct
pnfs_layoutdriver_type
filelayout_type
=
{
.
id
=
LAYOUT_NFSV4_1_FILES
,
.
name
=
"LAYOUT_NFSV4_1_FILES"
,
...
...
@@ -559,6 +862,9 @@ static struct pnfs_layoutdriver_type filelayout_type = {
.
alloc_lseg
=
filelayout_alloc_lseg
,
.
free_lseg
=
filelayout_free_lseg
,
.
pg_test
=
filelayout_pg_test
,
.
mark_pnfs_commit
=
filelayout_mark_pnfs_commit
,
.
choose_commit_list
=
filelayout_choose_commit_list
,
.
commit_pagelist
=
filelayout_commit_pagelist
,
.
read_pagelist
=
filelayout_read_pagelist
,
.
write_pagelist
=
filelayout_write_pagelist
,
};
...
...
fs/nfs/nfs4filelayout.h
View file @
0acd2201
...
...
@@ -79,6 +79,8 @@ struct nfs4_filelayout_segment {
struct
nfs4_file_layout_dsaddr
*
dsaddr
;
/* Point to GETDEVINFO data */
unsigned
int
num_fh
;
struct
nfs_fh
**
fh_array
;
struct
list_head
*
commit_buckets
;
/* Sort commits to ds */
int
number_of_buckets
;
};
static
inline
struct
nfs4_filelayout_segment
*
...
...
fs/nfs/nfs4filelayoutdev.c
View file @
0acd2201
...
...
@@ -261,7 +261,7 @@ nfs4_pnfs_ds_add(struct inode *inode, u32 ip_addr, u32 port)
* Currently only support ipv4, and one multi-path address.
*/
static
struct
nfs4_pnfs_ds
*
decode_and_add_ds
(
__be32
**
p
p
,
struct
inode
*
inode
)
decode_and_add_ds
(
struct
xdr_stream
*
stream
p
,
struct
inode
*
inode
)
{
struct
nfs4_pnfs_ds
*
ds
=
NULL
;
char
*
buf
;
...
...
@@ -269,25 +269,34 @@ decode_and_add_ds(__be32 **pp, struct inode *inode)
u32
ip_addr
,
port
;
int
nlen
,
rlen
,
i
;
int
tmp
[
2
];
__be32
*
r_netid
,
*
r_addr
,
*
p
=
*
p
p
;
__be32
*
p
;
/* r_netid */
p
=
xdr_inline_decode
(
streamp
,
4
);
if
(
unlikely
(
!
p
))
goto
out_err
;
nlen
=
be32_to_cpup
(
p
++
);
r_netid
=
p
;
p
+=
XDR_QUADLEN
(
nlen
);
/* r_addr */
rlen
=
be32_to_cpup
(
p
++
);
r_addr
=
p
;
p
+=
XDR_QUADLEN
(
rlen
);
*
pp
=
p
;
p
=
xdr_inline_decode
(
streamp
,
nlen
);
if
(
unlikely
(
!
p
))
goto
out_err
;
/* Check that netid is "tcp" */
if
(
nlen
!=
3
||
memcmp
((
char
*
)
r_netid
,
"tcp"
,
3
))
{
if
(
nlen
!=
3
||
memcmp
((
char
*
)
p
,
"tcp"
,
3
))
{
dprintk
(
"%s: ERROR: non ipv4 TCP r_netid
\n
"
,
__func__
);
goto
out_err
;
}
/* r_addr */
p
=
xdr_inline_decode
(
streamp
,
4
);
if
(
unlikely
(
!
p
))
goto
out_err
;
rlen
=
be32_to_cpup
(
p
);
p
=
xdr_inline_decode
(
streamp
,
rlen
);
if
(
unlikely
(
!
p
))
goto
out_err
;
/* ipv6 length plus port is legal */
if
(
rlen
>
INET6_ADDRSTRLEN
+
8
)
{
dprintk
(
"%s: Invalid address, length %d
\n
"
,
__func__
,
...
...
@@ -300,7 +309,7 @@ decode_and_add_ds(__be32 **pp, struct inode *inode)
goto
out_err
;
}
buf
[
rlen
]
=
'\0'
;
memcpy
(
buf
,
r_addr
,
rlen
);
memcpy
(
buf
,
p
,
rlen
);
/* replace the port dots with dashes for the in4_pton() delimiter*/
for
(
i
=
0
;
i
<
2
;
i
++
)
{
...
...
@@ -336,90 +345,154 @@ decode_and_add_ds(__be32 **pp, struct inode *inode)
static
struct
nfs4_file_layout_dsaddr
*
decode_device
(
struct
inode
*
ino
,
struct
pnfs_device
*
pdev
)
{
int
i
,
dummy
;
int
i
;
u32
cnt
,
num
;
u8
*
indexp
;
__be32
*
p
=
(
__be32
*
)
pdev
->
area
,
*
indicesp
;
struct
nfs4_file_layout_dsaddr
*
dsaddr
;
__be32
*
p
;
u8
*
stripe_indices
;
u8
max_stripe_index
;
struct
nfs4_file_layout_dsaddr
*
dsaddr
=
NULL
;
struct
xdr_stream
stream
;
struct
xdr_buf
buf
=
{
.
pages
=
pdev
->
pages
,
.
page_len
=
pdev
->
pglen
,
.
buflen
=
pdev
->
pglen
,
.
len
=
pdev
->
pglen
,
};
struct
page
*
scratch
;
/* set up xdr stream */
scratch
=
alloc_page
(
GFP_KERNEL
);
if
(
!
scratch
)
goto
out_err
;
xdr_init_decode
(
&
stream
,
&
buf
,
NULL
);
xdr_set_scratch_buffer
(
&
stream
,
page_address
(
scratch
),
PAGE_SIZE
);
/* Get the stripe count (number of stripe index) */
cnt
=
be32_to_cpup
(
p
++
);
p
=
xdr_inline_decode
(
&
stream
,
4
);
if
(
unlikely
(
!
p
))
goto
out_err_free_scratch
;
cnt
=
be32_to_cpup
(
p
);
dprintk
(
"%s stripe count %d
\n
"
,
__func__
,
cnt
);
if
(
cnt
>
NFS4_PNFS_MAX_STRIPE_CNT
)
{
printk
(
KERN_WARNING
"%s: stripe count %d greater than "
"supported maximum %d
\n
"
,
__func__
,
cnt
,
NFS4_PNFS_MAX_STRIPE_CNT
);
goto
out_err
;
goto
out_err_free_scratch
;
}
/* read stripe indices */
stripe_indices
=
kcalloc
(
cnt
,
sizeof
(
u8
),
GFP_KERNEL
);
if
(
!
stripe_indices
)
goto
out_err_free_scratch
;
p
=
xdr_inline_decode
(
&
stream
,
cnt
<<
2
);
if
(
unlikely
(
!
p
))
goto
out_err_free_stripe_indices
;
indexp
=
&
stripe_indices
[
0
];
max_stripe_index
=
0
;
for
(
i
=
0
;
i
<
cnt
;
i
++
)
{
*
indexp
=
be32_to_cpup
(
p
++
);
max_stripe_index
=
max
(
max_stripe_index
,
*
indexp
);
indexp
++
;
}
/* Check the multipath list count */
indicesp
=
p
;
p
+=
XDR_QUADLEN
(
cnt
<<
2
);
num
=
be32_to_cpup
(
p
++
);
p
=
xdr_inline_decode
(
&
stream
,
4
);
if
(
unlikely
(
!
p
))
goto
out_err_free_stripe_indices
;
num
=
be32_to_cpup
(
p
);
dprintk
(
"%s ds_num %u
\n
"
,
__func__
,
num
);
if
(
num
>
NFS4_PNFS_MAX_MULTI_CNT
)
{
printk
(
KERN_WARNING
"%s: multipath count %d greater than "
"supported maximum %d
\n
"
,
__func__
,
num
,
NFS4_PNFS_MAX_MULTI_CNT
);
goto
out_err
;
goto
out_err
_free_stripe_indices
;
}
/* validate stripe indices are all < num */
if
(
max_stripe_index
>=
num
)
{
printk
(
KERN_WARNING
"%s: stripe index %u >= num ds %u
\n
"
,
__func__
,
max_stripe_index
,
num
);
goto
out_err_free_stripe_indices
;
}
dsaddr
=
kzalloc
(
sizeof
(
*
dsaddr
)
+
(
sizeof
(
struct
nfs4_pnfs_ds
*
)
*
(
num
-
1
)),
GFP_KERNEL
);
if
(
!
dsaddr
)
goto
out_err
;
dsaddr
->
stripe_indices
=
kzalloc
(
sizeof
(
u8
)
*
cnt
,
GFP_KERNEL
);
if
(
!
dsaddr
->
stripe_indices
)
goto
out_err_free
;
goto
out_err_free_stripe_indices
;
dsaddr
->
stripe_count
=
cnt
;
dsaddr
->
stripe_indices
=
stripe_indices
;
stripe_indices
=
NULL
;
dsaddr
->
ds_num
=
num
;
memcpy
(
&
dsaddr
->
deviceid
,
&
pdev
->
dev_id
,
sizeof
(
pdev
->
dev_id
));
/* Go back an read stripe indices */
p
=
indicesp
;
indexp
=
&
dsaddr
->
stripe_indices
[
0
];
for
(
i
=
0
;
i
<
dsaddr
->
stripe_count
;
i
++
)
{
*
indexp
=
be32_to_cpup
(
p
++
);
if
(
*
indexp
>=
num
)
goto
out_err_free
;
indexp
++
;
}
/* Skip already read multipath list count */
p
++
;
for
(
i
=
0
;
i
<
dsaddr
->
ds_num
;
i
++
)
{
int
j
;
u32
mp_count
;
p
=
xdr_inline_decode
(
&
stream
,
4
);
if
(
unlikely
(
!
p
))
goto
out_err_free_deviceid
;
dummy
=
be32_to_cpup
(
p
++
);
/* multipath count */
if
(
dummy
>
1
)
{
mp_count
=
be32_to_cpup
(
p
);
/* multipath count */
if
(
mp_count
>
1
)
{
printk
(
KERN_WARNING
"%s: Multipath count %d not supported, "
"skipping all greater than 1
\n
"
,
__func__
,
dummy
);
mp_count
);
}
for
(
j
=
0
;
j
<
dummy
;
j
++
)
{
for
(
j
=
0
;
j
<
mp_count
;
j
++
)
{
if
(
j
==
0
)
{
dsaddr
->
ds_list
[
i
]
=
decode_and_add_ds
(
&
p
,
ino
);
dsaddr
->
ds_list
[
i
]
=
decode_and_add_ds
(
&
stream
,
ino
);
if
(
dsaddr
->
ds_list
[
i
]
==
NULL
)
goto
out_err_free
;
goto
out_err_free
_deviceid
;
}
else
{
u32
len
;
/* skip extra multipath */
len
=
be32_to_cpup
(
p
++
);
p
+=
XDR_QUADLEN
(
len
);
len
=
be32_to_cpup
(
p
++
);
p
+=
XDR_QUADLEN
(
len
);
continue
;
/* read len, skip */
p
=
xdr_inline_decode
(
&
stream
,
4
);
if
(
unlikely
(
!
p
))
goto
out_err_free_deviceid
;
len
=
be32_to_cpup
(
p
);
p
=
xdr_inline_decode
(
&
stream
,
len
);
if
(
unlikely
(
!
p
))
goto
out_err_free_deviceid
;
/* read len, skip */
p
=
xdr_inline_decode
(
&
stream
,
4
);
if
(
unlikely
(
!
p
))
goto
out_err_free_deviceid
;
len
=
be32_to_cpup
(
p
);
p
=
xdr_inline_decode
(
&
stream
,
len
);
if
(
unlikely
(
!
p
))
goto
out_err_free_deviceid
;
}
}
}
__free_page
(
scratch
);
return
dsaddr
;
out_err_free:
out_err_free
_deviceid
:
nfs4_fl_free_deviceid
(
dsaddr
);
/* stripe_indicies was part of dsaddr */
goto
out_err_free_scratch
;
out_err_free_stripe_indices:
kfree
(
stripe_indices
);
out_err_free_scratch:
__free_page
(
scratch
);
out_err:
dprintk
(
"%s ERROR: returning NULL
\n
"
,
__func__
);
return
NULL
;
...
...
@@ -498,11 +571,6 @@ get_device_info(struct inode *inode, struct nfs4_deviceid *dev_id)
goto
out_free
;
}
/* set pdev->area */
pdev
->
area
=
vmap
(
pages
,
max_pages
,
VM_MAP
,
PAGE_KERNEL
);
if
(
!
pdev
->
area
)
goto
out_free
;
memcpy
(
&
pdev
->
dev_id
,
dev_id
,
sizeof
(
*
dev_id
));
pdev
->
layout_type
=
LAYOUT_NFSV4_1_FILES
;
pdev
->
pages
=
pages
;
...
...
@@ -521,8 +589,6 @@ get_device_info(struct inode *inode, struct nfs4_deviceid *dev_id)
*/
dsaddr
=
decode_and_add_device
(
inode
,
pdev
);
out_free:
if
(
pdev
->
area
!=
NULL
)
vunmap
(
pdev
->
area
);
for
(
i
=
0
;
i
<
max_pages
;
i
++
)
__free_page
(
pages
[
i
]);
kfree
(
pages
);
...
...
fs/nfs/nfs4proc.c
View file @
0acd2201
...
...
@@ -3253,12 +3253,9 @@ static void nfs4_proc_write_setup(struct nfs_write_data *data, struct rpc_messag
msg
->
rpc_proc
=
&
nfs4_procedures
[
NFSPROC4_CLNT_WRITE
];
}
static
int
nfs4_commit_done
(
struct
rpc_task
*
task
,
struct
nfs_write_data
*
data
)
static
int
nfs4_commit_done
_cb
(
struct
rpc_task
*
task
,
struct
nfs_write_data
*
data
)
{
struct
inode
*
inode
=
data
->
inode
;
if
(
!
nfs4_sequence_done
(
task
,
&
data
->
res
.
seq_res
))
return
-
EAGAIN
;
if
(
nfs4_async_handle_error
(
task
,
NFS_SERVER
(
inode
),
NULL
)
==
-
EAGAIN
)
{
nfs_restart_rpc
(
task
,
NFS_SERVER
(
inode
)
->
nfs_client
);
...
...
@@ -3268,11 +3265,24 @@ static int nfs4_commit_done(struct rpc_task *task, struct nfs_write_data *data)
return
0
;
}
static
int
nfs4_commit_done
(
struct
rpc_task
*
task
,
struct
nfs_write_data
*
data
)
{
if
(
!
nfs4_sequence_done
(
task
,
&
data
->
res
.
seq_res
))
return
-
EAGAIN
;
return
data
->
write_done_cb
(
task
,
data
);
}
static
void
nfs4_proc_commit_setup
(
struct
nfs_write_data
*
data
,
struct
rpc_message
*
msg
)
{
struct
nfs_server
*
server
=
NFS_SERVER
(
data
->
inode
);
data
->
args
.
bitmask
=
server
->
cache_consistency_bitmask
;
if
(
data
->
lseg
)
{
data
->
args
.
bitmask
=
NULL
;
data
->
res
.
fattr
=
NULL
;
}
else
data
->
args
.
bitmask
=
server
->
cache_consistency_bitmask
;
if
(
!
data
->
write_done_cb
)
data
->
write_done_cb
=
nfs4_commit_done_cb
;
data
->
res
.
server
=
server
;
msg
->
rpc_proc
=
&
nfs4_procedures
[
NFSPROC4_CLNT_COMMIT
];
}
...
...
@@ -5608,8 +5618,6 @@ static void nfs4_layoutget_release(void *calldata)
struct
nfs4_layoutget
*
lgp
=
calldata
;
dprintk
(
"--> %s
\n
"
,
__func__
);
if
(
lgp
->
res
.
layout
.
buf
!=
NULL
)
free_page
((
unsigned
long
)
lgp
->
res
.
layout
.
buf
);
put_nfs_open_context
(
lgp
->
args
.
ctx
);
kfree
(
calldata
);
dprintk
(
"<-- %s
\n
"
,
__func__
);
...
...
@@ -5641,12 +5649,7 @@ int nfs4_proc_layoutget(struct nfs4_layoutget *lgp)
dprintk
(
"--> %s
\n
"
,
__func__
);
lgp
->
res
.
layout
.
buf
=
(
void
*
)
__get_free_page
(
GFP_NOFS
);
if
(
lgp
->
res
.
layout
.
buf
==
NULL
)
{
nfs4_layoutget_release
(
lgp
);
return
-
ENOMEM
;
}
lgp
->
res
.
layoutp
=
&
lgp
->
args
.
layout
;
lgp
->
res
.
seq_res
.
sr_slot
=
NULL
;
task
=
rpc_run_task
(
&
task_setup_data
);
if
(
IS_ERR
(
task
))
...
...
@@ -5698,6 +5701,100 @@ int nfs4_proc_getdeviceinfo(struct nfs_server *server, struct pnfs_device *pdev)
}
EXPORT_SYMBOL_GPL
(
nfs4_proc_getdeviceinfo
);
static
void
nfs4_layoutcommit_prepare
(
struct
rpc_task
*
task
,
void
*
calldata
)
{
struct
nfs4_layoutcommit_data
*
data
=
calldata
;
struct
nfs_server
*
server
=
NFS_SERVER
(
data
->
args
.
inode
);
if
(
nfs4_setup_sequence
(
server
,
&
data
->
args
.
seq_args
,
&
data
->
res
.
seq_res
,
1
,
task
))
return
;
rpc_call_start
(
task
);
}
static
void
nfs4_layoutcommit_done
(
struct
rpc_task
*
task
,
void
*
calldata
)
{
struct
nfs4_layoutcommit_data
*
data
=
calldata
;
struct
nfs_server
*
server
=
NFS_SERVER
(
data
->
args
.
inode
);
if
(
!
nfs4_sequence_done
(
task
,
&
data
->
res
.
seq_res
))
return
;
switch
(
task
->
tk_status
)
{
/* Just ignore these failures */
case
NFS4ERR_DELEG_REVOKED
:
/* layout was recalled */
case
NFS4ERR_BADIOMODE
:
/* no IOMODE_RW layout for range */
case
NFS4ERR_BADLAYOUT
:
/* no layout */
case
NFS4ERR_GRACE
:
/* loca_recalim always false */
task
->
tk_status
=
0
;
}
if
(
nfs4_async_handle_error
(
task
,
server
,
NULL
)
==
-
EAGAIN
)
{
nfs_restart_rpc
(
task
,
server
->
nfs_client
);
return
;
}
if
(
task
->
tk_status
==
0
)
nfs_post_op_update_inode_force_wcc
(
data
->
args
.
inode
,
data
->
res
.
fattr
);
}
static
void
nfs4_layoutcommit_release
(
void
*
calldata
)
{
struct
nfs4_layoutcommit_data
*
data
=
calldata
;
/* Matched by references in pnfs_set_layoutcommit */
put_lseg
(
data
->
lseg
);
put_rpccred
(
data
->
cred
);
kfree
(
data
);
}
static
const
struct
rpc_call_ops
nfs4_layoutcommit_ops
=
{
.
rpc_call_prepare
=
nfs4_layoutcommit_prepare
,
.
rpc_call_done
=
nfs4_layoutcommit_done
,
.
rpc_release
=
nfs4_layoutcommit_release
,
};
int
nfs4_proc_layoutcommit
(
struct
nfs4_layoutcommit_data
*
data
,
bool
sync
)
{
struct
rpc_message
msg
=
{
.
rpc_proc
=
&
nfs4_procedures
[
NFSPROC4_CLNT_LAYOUTCOMMIT
],
.
rpc_argp
=
&
data
->
args
,
.
rpc_resp
=
&
data
->
res
,
.
rpc_cred
=
data
->
cred
,
};
struct
rpc_task_setup
task_setup_data
=
{
.
task
=
&
data
->
task
,
.
rpc_client
=
NFS_CLIENT
(
data
->
args
.
inode
),
.
rpc_message
=
&
msg
,
.
callback_ops
=
&
nfs4_layoutcommit_ops
,
.
callback_data
=
data
,
.
flags
=
RPC_TASK_ASYNC
,
};
struct
rpc_task
*
task
;
int
status
=
0
;
dprintk
(
"NFS: %4d initiating layoutcommit call. sync %d "
"lbw: %llu inode %lu
\n
"
,
data
->
task
.
tk_pid
,
sync
,
data
->
args
.
lastbytewritten
,
data
->
args
.
inode
->
i_ino
);
task
=
rpc_run_task
(
&
task_setup_data
);
if
(
IS_ERR
(
task
))
return
PTR_ERR
(
task
);
if
(
sync
==
false
)
goto
out
;
status
=
nfs4_wait_for_completion_rpc_task
(
task
);
if
(
status
!=
0
)
goto
out
;
status
=
task
->
tk_status
;
out:
dprintk
(
"%s: status %d
\n
"
,
__func__
,
status
);
rpc_put_task
(
task
);
return
status
;
}
#endif
/* CONFIG_NFS_V4_1 */
struct
nfs4_state_recovery_ops
nfs40_reboot_recovery_ops
=
{
...
...
fs/nfs/nfs4xdr.c
View file @
0acd2201
...
...
@@ -327,6 +327,18 @@ static int nfs4_stat_to_errno(int);
#define decode_layoutget_maxsz (op_decode_hdr_maxsz + 8 + \
decode_stateid_maxsz + \
XDR_QUADLEN(PNFS_LAYOUT_MAXSIZE))
#define encode_layoutcommit_maxsz (op_encode_hdr_maxsz + \
2
/* offset */
+ \
2
/* length */
+ \
1
/* reclaim */
+ \
encode_stateid_maxsz + \
1
/* new offset (true) */
+ \
2
/* last byte written */
+ \
1
/* nt_timechanged (false) */
+ \
1
/* layoutupdate4 layout type */
+ \
1
/* NULL filelayout layoutupdate4 payload */
)
#define decode_layoutcommit_maxsz (op_decode_hdr_maxsz + 3)
#else
/* CONFIG_NFS_V4_1 */
#define encode_sequence_maxsz 0
#define decode_sequence_maxsz 0
...
...
@@ -738,6 +750,17 @@ static int nfs4_stat_to_errno(int);
decode_sequence_maxsz + \
decode_putfh_maxsz + \
decode_layoutget_maxsz)
#define NFS4_enc_layoutcommit_sz (compound_encode_hdr_maxsz + \
encode_sequence_maxsz +\
encode_putfh_maxsz + \
encode_layoutcommit_maxsz + \
encode_getattr_maxsz)
#define NFS4_dec_layoutcommit_sz (compound_decode_hdr_maxsz + \
decode_sequence_maxsz + \
decode_putfh_maxsz + \
decode_layoutcommit_maxsz + \
decode_getattr_maxsz)
const
u32
nfs41_maxwrite_overhead
=
((
RPC_MAX_HEADER_WITH_AUTH
+
compound_encode_hdr_maxsz
+
...
...
@@ -1839,6 +1862,34 @@ encode_layoutget(struct xdr_stream *xdr,
hdr
->
nops
++
;
hdr
->
replen
+=
decode_layoutget_maxsz
;
}
static
int
encode_layoutcommit
(
struct
xdr_stream
*
xdr
,
const
struct
nfs4_layoutcommit_args
*
args
,
struct
compound_hdr
*
hdr
)
{
__be32
*
p
;
dprintk
(
"%s: lbw: %llu type: %d
\n
"
,
__func__
,
args
->
lastbytewritten
,
NFS_SERVER
(
args
->
inode
)
->
pnfs_curr_ld
->
id
);
p
=
reserve_space
(
xdr
,
48
+
NFS4_STATEID_SIZE
);
*
p
++
=
cpu_to_be32
(
OP_LAYOUTCOMMIT
);
/* Only whole file layouts */
p
=
xdr_encode_hyper
(
p
,
0
);
/* offset */
p
=
xdr_encode_hyper
(
p
,
NFS4_MAX_UINT64
);
/* length */
*
p
++
=
cpu_to_be32
(
0
);
/* reclaim */
p
=
xdr_encode_opaque_fixed
(
p
,
args
->
stateid
.
data
,
NFS4_STATEID_SIZE
);
*
p
++
=
cpu_to_be32
(
1
);
/* newoffset = TRUE */
p
=
xdr_encode_hyper
(
p
,
args
->
lastbytewritten
);
*
p
++
=
cpu_to_be32
(
0
);
/* Never send time_modify_changed */
*
p
++
=
cpu_to_be32
(
NFS_SERVER
(
args
->
inode
)
->
pnfs_curr_ld
->
id
);
/* type */
*
p
++
=
cpu_to_be32
(
0
);
/* no file layout payload */
hdr
->
nops
++
;
hdr
->
replen
+=
decode_layoutcommit_maxsz
;
return
0
;
}
#endif
/* CONFIG_NFS_V4_1 */
/*
...
...
@@ -2317,7 +2368,8 @@ static void nfs4_xdr_enc_commit(struct rpc_rqst *req, struct xdr_stream *xdr,
encode_sequence
(
xdr
,
&
args
->
seq_args
,
&
hdr
);
encode_putfh
(
xdr
,
args
->
fh
,
&
hdr
);
encode_commit
(
xdr
,
args
,
&
hdr
);
encode_getfattr
(
xdr
,
args
->
bitmask
,
&
hdr
);
if
(
args
->
bitmask
)
encode_getfattr
(
xdr
,
args
->
bitmask
,
&
hdr
);
encode_nops
(
&
hdr
);
}
...
...
@@ -2645,7 +2697,31 @@ static void nfs4_xdr_enc_layoutget(struct rpc_rqst *req,
encode_sequence
(
xdr
,
&
args
->
seq_args
,
&
hdr
);
encode_putfh
(
xdr
,
NFS_FH
(
args
->
inode
),
&
hdr
);
encode_layoutget
(
xdr
,
args
,
&
hdr
);
xdr_inline_pages
(
&
req
->
rq_rcv_buf
,
hdr
.
replen
<<
2
,
args
->
layout
.
pages
,
0
,
args
->
layout
.
pglen
);
encode_nops
(
&
hdr
);
}
/*
* Encode LAYOUTCOMMIT request
*/
static
int
nfs4_xdr_enc_layoutcommit
(
struct
rpc_rqst
*
req
,
struct
xdr_stream
*
xdr
,
struct
nfs4_layoutcommit_args
*
args
)
{
struct
compound_hdr
hdr
=
{
.
minorversion
=
nfs4_xdr_minorversion
(
&
args
->
seq_args
),
};
encode_compound_hdr
(
xdr
,
req
,
&
hdr
);
encode_sequence
(
xdr
,
&
args
->
seq_args
,
&
hdr
);
encode_putfh
(
xdr
,
NFS_FH
(
args
->
inode
),
&
hdr
);
encode_layoutcommit
(
xdr
,
args
,
&
hdr
);
encode_getfattr
(
xdr
,
args
->
bitmask
,
&
hdr
);
encode_nops
(
&
hdr
);
return
0
;
}
#endif
/* CONFIG_NFS_V4_1 */
...
...
@@ -5063,6 +5139,9 @@ static int decode_layoutget(struct xdr_stream *xdr, struct rpc_rqst *req,
__be32
*
p
;
int
status
;
u32
layout_count
;
struct
xdr_buf
*
rcvbuf
=
&
req
->
rq_rcv_buf
;
struct
kvec
*
iov
=
rcvbuf
->
head
;
u32
hdrlen
,
recvd
;
status
=
decode_op_hdr
(
xdr
,
OP_LAYOUTGET
);
if
(
status
)
...
...
@@ -5079,17 +5158,14 @@ static int decode_layoutget(struct xdr_stream *xdr, struct rpc_rqst *req,
return
-
EINVAL
;
}
p
=
xdr_inline_decode
(
xdr
,
2
4
);
p
=
xdr_inline_decode
(
xdr
,
2
8
);
if
(
unlikely
(
!
p
))
goto
out_overflow
;
p
=
xdr_decode_hyper
(
p
,
&
res
->
range
.
offset
);
p
=
xdr_decode_hyper
(
p
,
&
res
->
range
.
length
);
res
->
range
.
iomode
=
be32_to_cpup
(
p
++
);
res
->
type
=
be32_to_cpup
(
p
++
);
status
=
decode_opaque_inline
(
xdr
,
&
res
->
layout
.
len
,
(
char
**
)
&
p
);
if
(
unlikely
(
status
))
return
status
;
res
->
layoutp
->
len
=
be32_to_cpup
(
p
);
dprintk
(
"%s roff:%lu rlen:%lu riomode:%d, lo_type:0x%x, lo.len:%d
\n
"
,
__func__
,
...
...
@@ -5097,12 +5173,18 @@ static int decode_layoutget(struct xdr_stream *xdr, struct rpc_rqst *req,
(
unsigned
long
)
res
->
range
.
length
,
res
->
range
.
iomode
,
res
->
type
,
res
->
layout
.
len
);
res
->
layoutp
->
len
);
hdrlen
=
(
u8
*
)
xdr
->
p
-
(
u8
*
)
iov
->
iov_base
;
recvd
=
req
->
rq_rcv_buf
.
len
-
hdrlen
;
if
(
res
->
layoutp
->
len
>
recvd
)
{
dprintk
(
"NFS: server cheating in layoutget reply: "
"layout len %u > recvd %u
\n
"
,
res
->
layoutp
->
len
,
recvd
);
return
-
EINVAL
;
}
/* nfs4_proc_layoutget allocated a single page */
if
(
res
->
layout
.
len
>
PAGE_SIZE
)
return
-
ENOMEM
;
memcpy
(
res
->
layout
.
buf
,
p
,
res
->
layout
.
len
);
xdr_read_pages
(
xdr
,
res
->
layoutp
->
len
);
if
(
layout_count
>
1
)
{
/* We only handle a length one array at the moment. Any
...
...
@@ -5119,6 +5201,35 @@ static int decode_layoutget(struct xdr_stream *xdr, struct rpc_rqst *req,
print_overflow_msg
(
__func__
,
xdr
);
return
-
EIO
;
}
static
int
decode_layoutcommit
(
struct
xdr_stream
*
xdr
,
struct
rpc_rqst
*
req
,
struct
nfs4_layoutcommit_res
*
res
)
{
__be32
*
p
;
__u32
sizechanged
;
int
status
;
status
=
decode_op_hdr
(
xdr
,
OP_LAYOUTCOMMIT
);
if
(
status
)
return
status
;
p
=
xdr_inline_decode
(
xdr
,
4
);
if
(
unlikely
(
!
p
))
goto
out_overflow
;
sizechanged
=
be32_to_cpup
(
p
);
if
(
sizechanged
)
{
/* throw away new size */
p
=
xdr_inline_decode
(
xdr
,
8
);
if
(
unlikely
(
!
p
))
goto
out_overflow
;
}
return
0
;
out_overflow:
print_overflow_msg
(
__func__
,
xdr
);
return
-
EIO
;
}
#endif
/* CONFIG_NFS_V4_1 */
/*
...
...
@@ -5836,8 +5947,9 @@ static int nfs4_xdr_dec_commit(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
status
=
decode_commit
(
xdr
,
res
);
if
(
status
)
goto
out
;
decode_getfattr
(
xdr
,
res
->
fattr
,
res
->
server
,
!
RPC_IS_ASYNC
(
rqstp
->
rq_task
));
if
(
res
->
fattr
)
decode_getfattr
(
xdr
,
res
->
fattr
,
res
->
server
,
!
RPC_IS_ASYNC
(
rqstp
->
rq_task
));
out:
return
status
;
}
...
...
@@ -6205,6 +6317,34 @@ static int nfs4_xdr_dec_layoutget(struct rpc_rqst *rqstp,
out:
return
status
;
}
/*
* Decode LAYOUTCOMMIT response
*/
static
int
nfs4_xdr_dec_layoutcommit
(
struct
rpc_rqst
*
rqstp
,
struct
xdr_stream
*
xdr
,
struct
nfs4_layoutcommit_res
*
res
)
{
struct
compound_hdr
hdr
;
int
status
;
status
=
decode_compound_hdr
(
xdr
,
&
hdr
);
if
(
status
)
goto
out
;
status
=
decode_sequence
(
xdr
,
&
res
->
seq_res
,
rqstp
);
if
(
status
)
goto
out
;
status
=
decode_putfh
(
xdr
);
if
(
status
)
goto
out
;
status
=
decode_layoutcommit
(
xdr
,
rqstp
,
res
);
if
(
status
)
goto
out
;
decode_getfattr
(
xdr
,
res
->
fattr
,
res
->
server
,
!
RPC_IS_ASYNC
(
rqstp
->
rq_task
));
out:
return
status
;
}
#endif
/* CONFIG_NFS_V4_1 */
/**
...
...
@@ -6403,6 +6543,7 @@ struct rpc_procinfo nfs4_procedures[] = {
PROC
(
RECLAIM_COMPLETE
,
enc_reclaim_complete
,
dec_reclaim_complete
),
PROC
(
GETDEVICEINFO
,
enc_getdeviceinfo
,
dec_getdeviceinfo
),
PROC
(
LAYOUTGET
,
enc_layoutget
,
dec_layoutget
),
PROC
(
LAYOUTCOMMIT
,
enc_layoutcommit
,
dec_layoutcommit
),
#endif
/* CONFIG_NFS_V4_1 */
};
...
...
fs/nfs/pagelist.c
View file @
0acd2201
...
...
@@ -223,6 +223,7 @@ void nfs_pageio_init(struct nfs_pageio_descriptor *desc,
desc
->
pg_count
=
0
;
desc
->
pg_bsize
=
bsize
;
desc
->
pg_base
=
0
;
desc
->
pg_moreio
=
0
;
desc
->
pg_inode
=
inode
;
desc
->
pg_doio
=
doio
;
desc
->
pg_ioflags
=
io_flags
;
...
...
@@ -335,9 +336,11 @@ int nfs_pageio_add_request(struct nfs_pageio_descriptor *desc,
struct
nfs_page
*
req
)
{
while
(
!
nfs_pageio_do_add_request
(
desc
,
req
))
{
desc
->
pg_moreio
=
1
;
nfs_pageio_doio
(
desc
);
if
(
desc
->
pg_error
<
0
)
return
0
;
desc
->
pg_moreio
=
0
;
}
return
1
;
}
...
...
@@ -395,6 +398,7 @@ int nfs_scan_list(struct nfs_inode *nfsi,
pgoff_t
idx_end
;
int
found
,
i
;
int
res
;
struct
list_head
*
list
;
res
=
0
;
if
(
npages
==
0
)
...
...
@@ -415,10 +419,10 @@ int nfs_scan_list(struct nfs_inode *nfsi,
idx_start
=
req
->
wb_index
+
1
;
if
(
nfs_set_page_tag_locked
(
req
))
{
kref_get
(
&
req
->
wb_kref
);
nfs_list_remove_request
(
req
);
radix_tree_tag_clear
(
&
nfsi
->
nfs_page_tree
,
req
->
wb_index
,
tag
);
nfs_list_add_request
(
req
,
dst
);
list
=
pnfs_choose_commit_list
(
req
,
dst
);
nfs_list_add_request
(
req
,
list
);
res
++
;
if
(
res
==
INT_MAX
)
goto
out
;
...
...
fs/nfs/pnfs.c
View file @
0acd2201
...
...
@@ -259,6 +259,7 @@ put_lseg(struct pnfs_layout_segment *lseg)
pnfs_free_lseg_list
(
&
free_me
);
}
}
EXPORT_SYMBOL_GPL
(
put_lseg
);
static
bool
should_free_lseg
(
u32
lseg_iomode
,
u32
recall_iomode
)
...
...
@@ -471,6 +472,9 @@ send_layoutget(struct pnfs_layout_hdr *lo,
struct
nfs_server
*
server
=
NFS_SERVER
(
ino
);
struct
nfs4_layoutget
*
lgp
;
struct
pnfs_layout_segment
*
lseg
=
NULL
;
struct
page
**
pages
=
NULL
;
int
i
;
u32
max_resp_sz
,
max_pages
;
dprintk
(
"--> %s
\n
"
,
__func__
);
...
...
@@ -478,6 +482,21 @@ send_layoutget(struct pnfs_layout_hdr *lo,
lgp
=
kzalloc
(
sizeof
(
*
lgp
),
GFP_KERNEL
);
if
(
lgp
==
NULL
)
return
NULL
;
/* allocate pages for xdr post processing */
max_resp_sz
=
server
->
nfs_client
->
cl_session
->
fc_attrs
.
max_resp_sz
;
max_pages
=
max_resp_sz
>>
PAGE_SHIFT
;
pages
=
kzalloc
(
max_pages
*
sizeof
(
struct
page
*
),
GFP_KERNEL
);
if
(
!
pages
)
goto
out_err_free
;
for
(
i
=
0
;
i
<
max_pages
;
i
++
)
{
pages
[
i
]
=
alloc_page
(
GFP_KERNEL
);
if
(
!
pages
[
i
])
goto
out_err_free
;
}
lgp
->
args
.
minlength
=
NFS4_MAX_UINT64
;
lgp
->
args
.
maxcount
=
PNFS_LAYOUT_MAXSIZE
;
lgp
->
args
.
range
.
iomode
=
iomode
;
...
...
@@ -486,6 +505,8 @@ send_layoutget(struct pnfs_layout_hdr *lo,
lgp
->
args
.
type
=
server
->
pnfs_curr_ld
->
id
;
lgp
->
args
.
inode
=
ino
;
lgp
->
args
.
ctx
=
get_nfs_open_context
(
ctx
);
lgp
->
args
.
layout
.
pages
=
pages
;
lgp
->
args
.
layout
.
pglen
=
max_pages
*
PAGE_SIZE
;
lgp
->
lsegpp
=
&
lseg
;
/* Synchronously retrieve layout information from server and
...
...
@@ -496,7 +517,26 @@ send_layoutget(struct pnfs_layout_hdr *lo,
/* remember that LAYOUTGET failed and suspend trying */
set_bit
(
lo_fail_bit
(
iomode
),
&
lo
->
plh_flags
);
}
/* free xdr pages */
for
(
i
=
0
;
i
<
max_pages
;
i
++
)
__free_page
(
pages
[
i
]);
kfree
(
pages
);
return
lseg
;
out_err_free:
/* free any allocated xdr pages, lgp as it's not used */
if
(
pages
)
{
for
(
i
=
0
;
i
<
max_pages
;
i
++
)
{
if
(
!
pages
[
i
])
break
;
__free_page
(
pages
[
i
]);
}
kfree
(
pages
);
}
kfree
(
lgp
);
return
NULL
;
}
bool
pnfs_roc
(
struct
inode
*
ino
)
...
...
@@ -945,3 +985,105 @@ pnfs_try_to_read_data(struct nfs_read_data *rdata,
dprintk
(
"%s End (trypnfs:%d)
\n
"
,
__func__
,
trypnfs
);
return
trypnfs
;
}
/*
* Currently there is only one (whole file) write lseg.
*/
static
struct
pnfs_layout_segment
*
pnfs_list_write_lseg
(
struct
inode
*
inode
)
{
struct
pnfs_layout_segment
*
lseg
,
*
rv
=
NULL
;
list_for_each_entry
(
lseg
,
&
NFS_I
(
inode
)
->
layout
->
plh_segs
,
pls_list
)
if
(
lseg
->
pls_range
.
iomode
==
IOMODE_RW
)
rv
=
lseg
;
return
rv
;
}
void
pnfs_set_layoutcommit
(
struct
nfs_write_data
*
wdata
)
{
struct
nfs_inode
*
nfsi
=
NFS_I
(
wdata
->
inode
);
loff_t
end_pos
=
wdata
->
args
.
offset
+
wdata
->
res
.
count
;
spin_lock
(
&
nfsi
->
vfs_inode
.
i_lock
);
if
(
!
test_and_set_bit
(
NFS_INO_LAYOUTCOMMIT
,
&
nfsi
->
flags
))
{
/* references matched in nfs4_layoutcommit_release */
get_lseg
(
wdata
->
lseg
);
wdata
->
lseg
->
pls_lc_cred
=
get_rpccred
(
wdata
->
args
.
context
->
state
->
owner
->
so_cred
);
mark_inode_dirty_sync
(
wdata
->
inode
);
dprintk
(
"%s: Set layoutcommit for inode %lu "
,
__func__
,
wdata
->
inode
->
i_ino
);
}
if
(
end_pos
>
wdata
->
lseg
->
pls_end_pos
)
wdata
->
lseg
->
pls_end_pos
=
end_pos
;
spin_unlock
(
&
nfsi
->
vfs_inode
.
i_lock
);
}
EXPORT_SYMBOL_GPL
(
pnfs_set_layoutcommit
);
/*
* For the LAYOUT4_NFSV4_1_FILES layout type, NFS_DATA_SYNC WRITEs and
* NFS_UNSTABLE WRITEs with a COMMIT to data servers must store enough
* data to disk to allow the server to recover the data if it crashes.
* LAYOUTCOMMIT is only needed when the NFL4_UFLG_COMMIT_THRU_MDS flag
* is off, and a COMMIT is sent to a data server, or
* if WRITEs to a data server return NFS_DATA_SYNC.
*/
int
pnfs_layoutcommit_inode
(
struct
inode
*
inode
,
bool
sync
)
{
struct
nfs4_layoutcommit_data
*
data
;
struct
nfs_inode
*
nfsi
=
NFS_I
(
inode
);
struct
pnfs_layout_segment
*
lseg
;
struct
rpc_cred
*
cred
;
loff_t
end_pos
;
int
status
=
0
;
dprintk
(
"--> %s inode %lu
\n
"
,
__func__
,
inode
->
i_ino
);
if
(
!
test_bit
(
NFS_INO_LAYOUTCOMMIT
,
&
nfsi
->
flags
))
return
0
;
/* Note kzalloc ensures data->res.seq_res.sr_slot == NULL */
data
=
kzalloc
(
sizeof
(
*
data
),
GFP_NOFS
);
if
(
!
data
)
{
mark_inode_dirty_sync
(
inode
);
status
=
-
ENOMEM
;
goto
out
;
}
spin_lock
(
&
inode
->
i_lock
);
if
(
!
test_and_clear_bit
(
NFS_INO_LAYOUTCOMMIT
,
&
nfsi
->
flags
))
{
spin_unlock
(
&
inode
->
i_lock
);
kfree
(
data
);
goto
out
;
}
/*
* Currently only one (whole file) write lseg which is referenced
* in pnfs_set_layoutcommit and will be found.
*/
lseg
=
pnfs_list_write_lseg
(
inode
);
end_pos
=
lseg
->
pls_end_pos
;
cred
=
lseg
->
pls_lc_cred
;
lseg
->
pls_end_pos
=
0
;
lseg
->
pls_lc_cred
=
NULL
;
memcpy
(
&
data
->
args
.
stateid
.
data
,
nfsi
->
layout
->
plh_stateid
.
data
,
sizeof
(
nfsi
->
layout
->
plh_stateid
.
data
));
spin_unlock
(
&
inode
->
i_lock
);
data
->
args
.
inode
=
inode
;
data
->
lseg
=
lseg
;
data
->
cred
=
cred
;
nfs_fattr_init
(
&
data
->
fattr
);
data
->
args
.
bitmask
=
NFS_SERVER
(
inode
)
->
cache_consistency_bitmask
;
data
->
res
.
fattr
=
&
data
->
fattr
;
data
->
args
.
lastbytewritten
=
end_pos
-
1
;
data
->
res
.
server
=
NFS_SERVER
(
inode
);
status
=
nfs4_proc_layoutcommit
(
data
,
sync
);
out:
dprintk
(
"<-- %s status %d
\n
"
,
__func__
,
status
);
return
status
;
}
fs/nfs/pnfs.h
View file @
0acd2201
...
...
@@ -43,6 +43,8 @@ struct pnfs_layout_segment {
atomic_t
pls_refcount
;
unsigned
long
pls_flags
;
struct
pnfs_layout_hdr
*
pls_layout
;
struct
rpc_cred
*
pls_lc_cred
;
/* LAYOUTCOMMIT credential */
loff_t
pls_end_pos
;
/* LAYOUTCOMMIT write end */
};
enum
pnfs_try_status
{
...
...
@@ -74,6 +76,13 @@ struct pnfs_layoutdriver_type {
/* test for nfs page cache coalescing */
int
(
*
pg_test
)(
struct
nfs_pageio_descriptor
*
,
struct
nfs_page
*
,
struct
nfs_page
*
);
/* Returns true if layoutdriver wants to divert this request to
* driver's commit routine.
*/
bool
(
*
mark_pnfs_commit
)(
struct
pnfs_layout_segment
*
lseg
);
struct
list_head
*
(
*
choose_commit_list
)
(
struct
nfs_page
*
req
);
int
(
*
commit_pagelist
)(
struct
inode
*
inode
,
struct
list_head
*
mds_pages
,
int
how
);
/*
* Return PNFS_ATTEMPTED to indicate the layout code has attempted
* I/O, else return PNFS_NOT_ATTEMPTED to fall back to normal NFS
...
...
@@ -100,7 +109,6 @@ struct pnfs_device {
unsigned
int
layout_type
;
unsigned
int
mincount
;
struct
page
**
pages
;
void
*
area
;
unsigned
int
pgbase
;
unsigned
int
pglen
;
};
...
...
@@ -145,7 +153,8 @@ bool pnfs_roc(struct inode *ino);
void
pnfs_roc_release
(
struct
inode
*
ino
);
void
pnfs_roc_set_barrier
(
struct
inode
*
ino
,
u32
barrier
);
bool
pnfs_roc_drain
(
struct
inode
*
ino
,
u32
*
barrier
);
void
pnfs_set_layoutcommit
(
struct
nfs_write_data
*
wdata
);
int
pnfs_layoutcommit_inode
(
struct
inode
*
inode
,
bool
sync
);
static
inline
int
lo_fail_bit
(
u32
iomode
)
{
...
...
@@ -169,6 +178,51 @@ static inline int pnfs_enabled_sb(struct nfs_server *nfss)
return
nfss
->
pnfs_curr_ld
!=
NULL
;
}
static
inline
void
pnfs_mark_request_commit
(
struct
nfs_page
*
req
,
struct
pnfs_layout_segment
*
lseg
)
{
if
(
lseg
)
{
struct
pnfs_layoutdriver_type
*
ld
;
ld
=
NFS_SERVER
(
req
->
wb_page
->
mapping
->
host
)
->
pnfs_curr_ld
;
if
(
ld
->
mark_pnfs_commit
&&
ld
->
mark_pnfs_commit
(
lseg
))
{
set_bit
(
PG_PNFS_COMMIT
,
&
req
->
wb_flags
);
req
->
wb_commit_lseg
=
get_lseg
(
lseg
);
}
}
}
static
inline
int
pnfs_commit_list
(
struct
inode
*
inode
,
struct
list_head
*
mds_pages
,
int
how
)
{
if
(
!
test_and_clear_bit
(
NFS_INO_PNFS_COMMIT
,
&
NFS_I
(
inode
)
->
flags
))
return
PNFS_NOT_ATTEMPTED
;
return
NFS_SERVER
(
inode
)
->
pnfs_curr_ld
->
commit_pagelist
(
inode
,
mds_pages
,
how
);
}
static
inline
struct
list_head
*
pnfs_choose_commit_list
(
struct
nfs_page
*
req
,
struct
list_head
*
mds
)
{
struct
list_head
*
rv
;
if
(
test_and_clear_bit
(
PG_PNFS_COMMIT
,
&
req
->
wb_flags
))
{
struct
inode
*
inode
=
req
->
wb_commit_lseg
->
pls_layout
->
plh_inode
;
set_bit
(
NFS_INO_PNFS_COMMIT
,
&
NFS_I
(
inode
)
->
flags
);
rv
=
NFS_SERVER
(
inode
)
->
pnfs_curr_ld
->
choose_commit_list
(
req
);
/* matched by ref taken when PG_PNFS_COMMIT is set */
put_lseg
(
req
->
wb_commit_lseg
);
}
else
rv
=
mds
;
return
rv
;
}
static
inline
void
pnfs_clear_request_commit
(
struct
nfs_page
*
req
)
{
if
(
test_and_clear_bit
(
PG_PNFS_COMMIT
,
&
req
->
wb_flags
))
put_lseg
(
req
->
wb_commit_lseg
);
}
#else
/* CONFIG_NFS_V4_1 */
static
inline
void
pnfs_destroy_all_layouts
(
struct
nfs_client
*
clp
)
...
...
@@ -252,6 +306,31 @@ pnfs_pageio_init_write(struct nfs_pageio_descriptor *pgio, struct inode *ino)
pgio
->
pg_test
=
NULL
;
}
static
inline
void
pnfs_mark_request_commit
(
struct
nfs_page
*
req
,
struct
pnfs_layout_segment
*
lseg
)
{
}
static
inline
int
pnfs_commit_list
(
struct
inode
*
inode
,
struct
list_head
*
mds_pages
,
int
how
)
{
return
PNFS_NOT_ATTEMPTED
;
}
static
inline
struct
list_head
*
pnfs_choose_commit_list
(
struct
nfs_page
*
req
,
struct
list_head
*
mds
)
{
return
mds
;
}
static
inline
void
pnfs_clear_request_commit
(
struct
nfs_page
*
req
)
{
}
static
inline
int
pnfs_layoutcommit_inode
(
struct
inode
*
inode
,
bool
sync
)
{
return
0
;
}
#endif
/* CONFIG_NFS_V4_1 */
#endif
/* FS_NFS_PNFS_H */
fs/nfs/write.c
View file @
0acd2201
...
...
@@ -59,6 +59,7 @@ struct nfs_write_data *nfs_commitdata_alloc(void)
}
return
p
;
}
EXPORT_SYMBOL_GPL
(
nfs_commitdata_alloc
);
void
nfs_commit_free
(
struct
nfs_write_data
*
p
)
{
...
...
@@ -66,6 +67,7 @@ void nfs_commit_free(struct nfs_write_data *p)
kfree
(
p
->
pagevec
);
mempool_free
(
p
,
nfs_commit_mempool
);
}
EXPORT_SYMBOL_GPL
(
nfs_commit_free
);
struct
nfs_write_data
*
nfs_writedata_alloc
(
unsigned
int
pagecount
)
{
...
...
@@ -179,8 +181,8 @@ static int wb_priority(struct writeback_control *wbc)
if
(
wbc
->
for_reclaim
)
return
FLUSH_HIGHPRI
|
FLUSH_STABLE
;
if
(
wbc
->
for_kupdate
||
wbc
->
for_background
)
return
FLUSH_LOWPRI
;
return
0
;
return
FLUSH_LOWPRI
|
FLUSH_COND_STABLE
;
return
FLUSH_COND_STABLE
;
}
/*
...
...
@@ -441,7 +443,7 @@ nfs_mark_request_dirty(struct nfs_page *req)
* Add a request to the inode's commit list.
*/
static
void
nfs_mark_request_commit
(
struct
nfs_page
*
req
)
nfs_mark_request_commit
(
struct
nfs_page
*
req
,
struct
pnfs_layout_segment
*
lseg
)
{
struct
inode
*
inode
=
req
->
wb_context
->
path
.
dentry
->
d_inode
;
struct
nfs_inode
*
nfsi
=
NFS_I
(
inode
);
...
...
@@ -453,6 +455,7 @@ nfs_mark_request_commit(struct nfs_page *req)
NFS_PAGE_TAG_COMMIT
);
nfsi
->
ncommit
++
;
spin_unlock
(
&
inode
->
i_lock
);
pnfs_mark_request_commit
(
req
,
lseg
);
inc_zone_page_state
(
req
->
wb_page
,
NR_UNSTABLE_NFS
);
inc_bdi_stat
(
req
->
wb_page
->
mapping
->
backing_dev_info
,
BDI_RECLAIMABLE
);
__mark_inode_dirty
(
inode
,
I_DIRTY_DATASYNC
);
...
...
@@ -474,14 +477,18 @@ nfs_clear_request_commit(struct nfs_page *req)
static
inline
int
nfs_write_need_commit
(
struct
nfs_write_data
*
data
)
{
return
data
->
verf
.
committed
!=
NFS_FILE_SYNC
;
if
(
data
->
verf
.
committed
==
NFS_DATA_SYNC
)
return
data
->
lseg
==
NULL
;
else
return
data
->
verf
.
committed
!=
NFS_FILE_SYNC
;
}
static
inline
int
nfs_reschedule_unstable_write
(
struct
nfs_page
*
req
)
int
nfs_reschedule_unstable_write
(
struct
nfs_page
*
req
,
struct
nfs_write_data
*
data
)
{
if
(
test_and_clear_bit
(
PG_NEED_COMMIT
,
&
req
->
wb_flags
))
{
nfs_mark_request_commit
(
req
);
nfs_mark_request_commit
(
req
,
data
->
lseg
);
return
1
;
}
if
(
test_and_clear_bit
(
PG_NEED_RESCHED
,
&
req
->
wb_flags
))
{
...
...
@@ -492,7 +499,7 @@ int nfs_reschedule_unstable_write(struct nfs_page *req)
}
#else
static
inline
void
nfs_mark_request_commit
(
struct
nfs_page
*
req
)
nfs_mark_request_commit
(
struct
nfs_page
*
req
,
struct
pnfs_layout_segment
*
lseg
)
{
}
...
...
@@ -509,7 +516,8 @@ int nfs_write_need_commit(struct nfs_write_data *data)
}
static
inline
int
nfs_reschedule_unstable_write
(
struct
nfs_page
*
req
)
int
nfs_reschedule_unstable_write
(
struct
nfs_page
*
req
,
struct
nfs_write_data
*
data
)
{
return
0
;
}
...
...
@@ -612,9 +620,11 @@ static struct nfs_page *nfs_try_to_update_request(struct inode *inode,
}
if
(
nfs_clear_request_commit
(
req
)
&&
radix_tree_tag_clear
(
&
NFS_I
(
inode
)
->
nfs_page_tree
,
req
->
wb_index
,
NFS_PAGE_TAG_COMMIT
)
!=
NULL
)
radix_tree_tag_clear
(
&
NFS_I
(
inode
)
->
nfs_page_tree
,
req
->
wb_index
,
NFS_PAGE_TAG_COMMIT
)
!=
NULL
)
{
NFS_I
(
inode
)
->
ncommit
--
;
pnfs_clear_request_commit
(
req
);
}
/* Okay, the request matches. Update the region */
if
(
offset
<
req
->
wb_offset
)
{
...
...
@@ -762,11 +772,12 @@ int nfs_updatepage(struct file *file, struct page *page,
return
status
;
}
static
void
nfs_writepage_release
(
struct
nfs_page
*
req
)
static
void
nfs_writepage_release
(
struct
nfs_page
*
req
,
struct
nfs_write_data
*
data
)
{
struct
page
*
page
=
req
->
wb_page
;
if
(
PageError
(
req
->
wb_page
)
||
!
nfs_reschedule_unstable_write
(
req
))
if
(
PageError
(
req
->
wb_page
)
||
!
nfs_reschedule_unstable_write
(
req
,
data
))
nfs_inode_remove_request
(
req
);
nfs_clear_page_tag_locked
(
req
);
nfs_end_page_writeback
(
page
);
...
...
@@ -863,7 +874,7 @@ static int nfs_write_rpcsetup(struct nfs_page *req,
data
->
args
.
context
=
get_nfs_open_context
(
req
->
wb_context
);
data
->
args
.
lock_context
=
req
->
wb_lock_context
;
data
->
args
.
stable
=
NFS_UNSTABLE
;
if
(
how
&
FLUSH_STABLE
)
{
if
(
how
&
(
FLUSH_STABLE
|
FLUSH_COND_STABLE
)
)
{
data
->
args
.
stable
=
NFS_DATA_SYNC
;
if
(
!
nfs_need_commit
(
NFS_I
(
inode
)))
data
->
args
.
stable
=
NFS_FILE_SYNC
;
...
...
@@ -912,6 +923,12 @@ static int nfs_flush_multi(struct nfs_pageio_descriptor *desc)
nfs_list_remove_request
(
req
);
if
((
desc
->
pg_ioflags
&
FLUSH_COND_STABLE
)
&&
(
desc
->
pg_moreio
||
NFS_I
(
desc
->
pg_inode
)
->
ncommit
||
desc
->
pg_count
>
wsize
))
desc
->
pg_ioflags
&=
~
FLUSH_COND_STABLE
;
nbytes
=
desc
->
pg_count
;
do
{
size_t
len
=
min
(
nbytes
,
wsize
);
...
...
@@ -1002,6 +1019,10 @@ static int nfs_flush_one(struct nfs_pageio_descriptor *desc)
if
((
!
lseg
)
&&
list_is_singular
(
&
data
->
pages
))
lseg
=
pnfs_update_layout
(
desc
->
pg_inode
,
req
->
wb_context
,
IOMODE_RW
);
if
((
desc
->
pg_ioflags
&
FLUSH_COND_STABLE
)
&&
(
desc
->
pg_moreio
||
NFS_I
(
desc
->
pg_inode
)
->
ncommit
))
desc
->
pg_ioflags
&=
~
FLUSH_COND_STABLE
;
/* Set up the argument struct */
ret
=
nfs_write_rpcsetup
(
req
,
data
,
&
nfs_write_full_ops
,
desc
->
pg_count
,
0
,
lseg
,
desc
->
pg_ioflags
);
out:
...
...
@@ -1074,7 +1095,7 @@ static void nfs_writeback_release_partial(void *calldata)
out:
if
(
atomic_dec_and_test
(
&
req
->
wb_complete
))
nfs_writepage_release
(
req
);
nfs_writepage_release
(
req
,
data
);
nfs_writedata_release
(
calldata
);
}
...
...
@@ -1141,7 +1162,7 @@ static void nfs_writeback_release_full(void *calldata)
if
(
nfs_write_need_commit
(
data
))
{
memcpy
(
&
req
->
wb_verf
,
&
data
->
verf
,
sizeof
(
req
->
wb_verf
));
nfs_mark_request_commit
(
req
);
nfs_mark_request_commit
(
req
,
data
->
lseg
);
dprintk
(
" marked for commit
\n
"
);
goto
next
;
}
...
...
@@ -1251,57 +1272,82 @@ void nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data)
#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
static
int
nfs_commit_set_lock
(
struct
nfs_inode
*
nfsi
,
int
may_wait
)
{
int
ret
;
if
(
!
test_and_set_bit
(
NFS_INO_COMMIT
,
&
nfsi
->
flags
))
return
1
;
if
(
may_wait
&&
!
out_of_line_wait_on_bit_lock
(
&
nfsi
->
flags
,
NFS_INO_COMMIT
,
nfs_wait_bit_killable
,
TASK_KILLABLE
))
return
1
;
return
0
;
if
(
!
may_wait
)
return
0
;
ret
=
out_of_line_wait_on_bit_lock
(
&
nfsi
->
flags
,
NFS_INO_COMMIT
,
nfs_wait_bit_killable
,
TASK_KILLABLE
);
return
(
ret
<
0
)
?
ret
:
1
;
}
static
void
nfs_commit_clear_lock
(
struct
nfs_inode
*
nfsi
)
void
nfs_commit_clear_lock
(
struct
nfs_inode
*
nfsi
)
{
clear_bit
(
NFS_INO_COMMIT
,
&
nfsi
->
flags
);
smp_mb__after_clear_bit
();
wake_up_bit
(
&
nfsi
->
flags
,
NFS_INO_COMMIT
);
}
EXPORT_SYMBOL_GPL
(
nfs_commit_clear_lock
);
static
void
nfs_commitdata_release
(
void
*
data
)
void
nfs_commitdata_release
(
void
*
data
)
{
struct
nfs_write_data
*
wdata
=
data
;
put_lseg
(
wdata
->
lseg
);
put_nfs_open_context
(
wdata
->
args
.
context
);
nfs_commit_free
(
wdata
);
}
EXPORT_SYMBOL_GPL
(
nfs_commitdata_release
);
/*
* Set up the argument/result storage required for the RPC call.
*/
static
int
nfs_commit_rpcsetup
(
struct
list_head
*
head
,
struct
nfs_write_data
*
data
,
int
how
)
int
nfs_initiate_commit
(
struct
nfs_write_data
*
data
,
struct
rpc_clnt
*
clnt
,
const
struct
rpc_call_ops
*
call_ops
,
int
how
)
{
struct
nfs_page
*
first
=
nfs_list_entry
(
head
->
next
);
struct
inode
*
inode
=
first
->
wb_context
->
path
.
dentry
->
d_inode
;
int
priority
=
flush_task_priority
(
how
);
struct
rpc_task
*
task
;
int
priority
=
flush_task_priority
(
how
);
struct
rpc_message
msg
=
{
.
rpc_argp
=
&
data
->
args
,
.
rpc_resp
=
&
data
->
res
,
.
rpc_cred
=
first
->
wb_context
->
cred
,
.
rpc_cred
=
data
->
cred
,
};
struct
rpc_task_setup
task_setup_data
=
{
.
task
=
&
data
->
task
,
.
rpc_client
=
NFS_CLIENT
(
inode
)
,
.
rpc_client
=
clnt
,
.
rpc_message
=
&
msg
,
.
callback_ops
=
&
nfs_commit
_ops
,
.
callback_ops
=
call
_ops
,
.
callback_data
=
data
,
.
workqueue
=
nfsiod_workqueue
,
.
flags
=
RPC_TASK_ASYNC
,
.
priority
=
priority
,
};
/* Set up the initial task struct. */
NFS_PROTO
(
data
->
inode
)
->
commit_setup
(
data
,
&
msg
);
dprintk
(
"NFS: %5u initiated commit call
\n
"
,
data
->
task
.
tk_pid
);
task
=
rpc_run_task
(
&
task_setup_data
);
if
(
IS_ERR
(
task
))
return
PTR_ERR
(
task
);
if
(
how
&
FLUSH_SYNC
)
rpc_wait_for_completion_task
(
task
);
rpc_put_task
(
task
);
return
0
;
}
EXPORT_SYMBOL_GPL
(
nfs_initiate_commit
);
/*
* Set up the argument/result storage required for the RPC call.
*/
void
nfs_init_commit
(
struct
nfs_write_data
*
data
,
struct
list_head
*
head
,
struct
pnfs_layout_segment
*
lseg
)
{
struct
nfs_page
*
first
=
nfs_list_entry
(
head
->
next
);
struct
inode
*
inode
=
first
->
wb_context
->
path
.
dentry
->
d_inode
;
/* Set up the RPC argument and reply structs
* NB: take care not to mess about with data->commit et al. */
...
...
@@ -1309,7 +1355,9 @@ static int nfs_commit_rpcsetup(struct list_head *head,
list_splice_init
(
head
,
&
data
->
pages
);
data
->
inode
=
inode
;
data
->
cred
=
msg
.
rpc_cred
;
data
->
cred
=
first
->
wb_context
->
cred
;
data
->
lseg
=
lseg
;
/* reference transferred */
data
->
mds_ops
=
&
nfs_commit_ops
;
data
->
args
.
fh
=
NFS_FH
(
data
->
inode
);
/* Note: we always request a commit of the entire inode */
...
...
@@ -1320,20 +1368,25 @@ static int nfs_commit_rpcsetup(struct list_head *head,
data
->
res
.
fattr
=
&
data
->
fattr
;
data
->
res
.
verf
=
&
data
->
verf
;
nfs_fattr_init
(
&
data
->
fattr
);
}
EXPORT_SYMBOL_GPL
(
nfs_init_commit
);
/* Set up the initial task struct. */
NFS_PROTO
(
inode
)
->
commit_setup
(
data
,
&
msg
);
dprintk
(
"NFS: %5u initiated commit call
\n
"
,
data
->
task
.
tk_pid
)
;
void
nfs_retry_commit
(
struct
list_head
*
page_list
,
struct
pnfs_layout_segment
*
lseg
)
{
struct
nfs_page
*
req
;
task
=
rpc_run_task
(
&
task_setup_data
);
if
(
IS_ERR
(
task
))
return
PTR_ERR
(
task
);
if
(
how
&
FLUSH_SYNC
)
rpc_wait_for_completion_task
(
task
);
rpc_put_task
(
task
);
return
0
;
while
(
!
list_empty
(
page_list
))
{
req
=
nfs_list_entry
(
page_list
->
next
);
nfs_list_remove_request
(
req
);
nfs_mark_request_commit
(
req
,
lseg
);
dec_zone_page_state
(
req
->
wb_page
,
NR_UNSTABLE_NFS
);
dec_bdi_stat
(
req
->
wb_page
->
mapping
->
backing_dev_info
,
BDI_RECLAIMABLE
);
nfs_clear_page_tag_locked
(
req
);
}
}
EXPORT_SYMBOL_GPL
(
nfs_retry_commit
);
/*
* Commit dirty pages
...
...
@@ -1342,7 +1395,6 @@ static int
nfs_commit_list
(
struct
inode
*
inode
,
struct
list_head
*
head
,
int
how
)
{
struct
nfs_write_data
*
data
;
struct
nfs_page
*
req
;
data
=
nfs_commitdata_alloc
();
...
...
@@ -1350,17 +1402,10 @@ nfs_commit_list(struct inode *inode, struct list_head *head, int how)
goto
out_bad
;
/* Set up the argument struct */
return
nfs_commit_rpcsetup
(
head
,
data
,
how
);
nfs_init_commit
(
data
,
head
,
NULL
);
return
nfs_initiate_commit
(
data
,
NFS_CLIENT
(
inode
),
data
->
mds_ops
,
how
);
out_bad:
while
(
!
list_empty
(
head
))
{
req
=
nfs_list_entry
(
head
->
next
);
nfs_list_remove_request
(
req
);
nfs_mark_request_commit
(
req
);
dec_zone_page_state
(
req
->
wb_page
,
NR_UNSTABLE_NFS
);
dec_bdi_stat
(
req
->
wb_page
->
mapping
->
backing_dev_info
,
BDI_RECLAIMABLE
);
nfs_clear_page_tag_locked
(
req
);
}
nfs_retry_commit
(
head
,
NULL
);
nfs_commit_clear_lock
(
NFS_I
(
inode
));
return
-
ENOMEM
;
}
...
...
@@ -1380,10 +1425,9 @@ static void nfs_commit_done(struct rpc_task *task, void *calldata)
return
;
}
static
void
nfs_commit_release
(
void
*
call
data
)
void
nfs_commit_release_pages
(
struct
nfs_write_data
*
data
)
{
struct
nfs_write_data
*
data
=
calldata
;
struct
nfs_page
*
req
;
struct
nfs_page
*
req
;
int
status
=
data
->
task
.
tk_status
;
while
(
!
list_empty
(
&
data
->
pages
))
{
...
...
@@ -1417,6 +1461,14 @@ static void nfs_commit_release(void *calldata)
next:
nfs_clear_page_tag_locked
(
req
);
}
}
EXPORT_SYMBOL_GPL
(
nfs_commit_release_pages
);
static
void
nfs_commit_release
(
void
*
calldata
)
{
struct
nfs_write_data
*
data
=
calldata
;
nfs_commit_release_pages
(
data
);
nfs_commit_clear_lock
(
NFS_I
(
data
->
inode
));
nfs_commitdata_release
(
calldata
);
}
...
...
@@ -1433,23 +1485,30 @@ int nfs_commit_inode(struct inode *inode, int how)
{
LIST_HEAD
(
head
);
int
may_wait
=
how
&
FLUSH_SYNC
;
int
res
=
0
;
int
res
;
if
(
!
nfs_commit_set_lock
(
NFS_I
(
inode
),
may_wait
))
res
=
nfs_commit_set_lock
(
NFS_I
(
inode
),
may_wait
);
if
(
res
<=
0
)
goto
out_mark_dirty
;
spin_lock
(
&
inode
->
i_lock
);
res
=
nfs_scan_commit
(
inode
,
&
head
,
0
,
0
);
spin_unlock
(
&
inode
->
i_lock
);
if
(
res
)
{
int
error
=
nfs_commit_list
(
inode
,
&
head
,
how
);
int
error
;
error
=
pnfs_commit_list
(
inode
,
&
head
,
how
);
if
(
error
==
PNFS_NOT_ATTEMPTED
)
error
=
nfs_commit_list
(
inode
,
&
head
,
how
);
if
(
error
<
0
)
return
error
;
if
(
may_wait
)
wait_on_bit
(
&
NFS_I
(
inode
)
->
flags
,
NFS_INO_COMMIT
,
nfs_wait_bit_killable
,
TASK_KILLABLE
);
else
if
(
!
may_wait
)
goto
out_mark_dirty
;
error
=
wait_on_bit
(
&
NFS_I
(
inode
)
->
flags
,
NFS_INO_COMMIT
,
nfs_wait_bit_killable
,
TASK_KILLABLE
);
if
(
error
<
0
)
return
error
;
}
else
nfs_commit_clear_lock
(
NFS_I
(
inode
));
return
res
;
...
...
@@ -1503,7 +1562,22 @@ static int nfs_commit_unstable_pages(struct inode *inode, struct writeback_contr
int
nfs_write_inode
(
struct
inode
*
inode
,
struct
writeback_control
*
wbc
)
{
return
nfs_commit_unstable_pages
(
inode
,
wbc
);
int
ret
;
ret
=
nfs_commit_unstable_pages
(
inode
,
wbc
);
if
(
ret
>=
0
&&
test_bit
(
NFS_INO_LAYOUTCOMMIT
,
&
NFS_I
(
inode
)
->
flags
))
{
int
status
;
bool
sync
=
true
;
if
(
wbc
->
sync_mode
==
WB_SYNC_NONE
||
wbc
->
nonblocking
||
wbc
->
for_background
)
sync
=
false
;
status
=
pnfs_layoutcommit_inode
(
inode
,
sync
);
if
(
status
<
0
)
return
status
;
}
return
ret
;
}
/*
...
...
fs/nfs_common/nfsacl.c
View file @
0acd2201
...
...
@@ -117,7 +117,6 @@ int nfsacl_encode(struct xdr_buf *buf, unsigned int base, struct inode *inode,
* invoked in contexts where a memory allocation failure is
* fatal. Fortunately this fake ACL is small enough to
* construct on the stack. */
memset
(
acl2
,
0
,
sizeof
(
acl2
));
posix_acl_init
(
acl2
,
4
);
/* Insert entries in canonical order: other orders seem
...
...
include/linux/nfs4.h
View file @
0acd2201
...
...
@@ -561,6 +561,7 @@ enum {
NFSPROC4_CLNT_RECLAIM_COMPLETE
,
NFSPROC4_CLNT_LAYOUTGET
,
NFSPROC4_CLNT_GETDEVICEINFO
,
NFSPROC4_CLNT_LAYOUTCOMMIT
,
};
/* nfs41 types */
...
...
include/linux/nfs_fs.h
View file @
0acd2201
...
...
@@ -33,6 +33,8 @@
#define FLUSH_STABLE 4
/* commit to stable storage */
#define FLUSH_LOWPRI 8
/* low priority background flush */
#define FLUSH_HIGHPRI 16
/* high priority memory reclaim flush */
#define FLUSH_COND_STABLE 32
/* conditional stable write - only stable
* if everything fits in one RPC */
#ifdef __KERNEL__
...
...
@@ -93,8 +95,13 @@ struct nfs_open_context {
int
error
;
struct
list_head
list
;
};
struct
nfs_open_dir_context
{
struct
rpc_cred
*
cred
;
__u64
dir_cookie
;
__u64
dup_cookie
;
int
duped
;
};
/*
...
...
@@ -191,6 +198,7 @@ struct nfs_inode {
/* pNFS layout information */
struct
pnfs_layout_hdr
*
layout
;
atomic_t
commits_outstanding
;
#endif
/* CONFIG_NFS_V4*/
#ifdef CONFIG_NFS_FSCACHE
struct
fscache_cookie
*
fscache
;
...
...
@@ -219,6 +227,8 @@ struct nfs_inode {
#define NFS_INO_FSCACHE (5)
/* inode can be cached by FS-Cache */
#define NFS_INO_FSCACHE_LOCK (6)
/* FS-Cache cookie management lock */
#define NFS_INO_COMMIT (7)
/* inode is committing unstable writes */
#define NFS_INO_PNFS_COMMIT (8)
/* use pnfs code for commit */
#define NFS_INO_LAYOUTCOMMIT (9)
/* layoutcommit required */
static
inline
struct
nfs_inode
*
NFS_I
(
const
struct
inode
*
inode
)
{
...
...
include/linux/nfs_page.h
View file @
0acd2201
...
...
@@ -33,11 +33,15 @@ enum {
PG_CLEAN
,
PG_NEED_COMMIT
,
PG_NEED_RESCHED
,
PG_PNFS_COMMIT
,
};
struct
nfs_inode
;
struct
nfs_page
{
struct
list_head
wb_list
;
/* Defines state of page: */
union
{
struct
list_head
wb_list
;
/* Defines state of page: */
struct
pnfs_layout_segment
*
wb_commit_lseg
;
/* Used when PG_PNFS_COMMIT set */
};
struct
page
*
wb_page
;
/* page to read in/write out */
struct
nfs_open_context
*
wb_context
;
/* File state context info */
struct
nfs_lock_context
*
wb_lock_context
;
/* lock context info */
...
...
@@ -57,6 +61,7 @@ struct nfs_pageio_descriptor {
size_t
pg_count
;
size_t
pg_bsize
;
unsigned
int
pg_base
;
char
pg_moreio
;
struct
inode
*
pg_inode
;
int
(
*
pg_doio
)(
struct
nfs_pageio_descriptor
*
);
...
...
include/linux/nfs_xdr.h
View file @
0acd2201
...
...
@@ -195,8 +195,9 @@ struct nfs4_get_lease_time_res {
#define PNFS_LAYOUT_MAXSIZE 4096
struct
nfs4_layoutdriver_data
{
struct
page
**
pages
;
__u32
pglen
;
__u32
len
;
void
*
buf
;
};
struct
pnfs_layout_range
{
...
...
@@ -214,6 +215,7 @@ struct nfs4_layoutget_args {
struct
nfs_open_context
*
ctx
;
struct
nfs4_sequence_args
seq_args
;
nfs4_stateid
stateid
;
struct
nfs4_layoutdriver_data
layout
;
};
struct
nfs4_layoutget_res
{
...
...
@@ -221,8 +223,8 @@ struct nfs4_layoutget_res {
struct
pnfs_layout_range
range
;
__u32
type
;
nfs4_stateid
stateid
;
struct
nfs4_layoutdriver_data
layout
;
struct
nfs4_sequence_res
seq_res
;
struct
nfs4_layoutdriver_data
*
layoutp
;
};
struct
nfs4_layoutget
{
...
...
@@ -241,6 +243,29 @@ struct nfs4_getdeviceinfo_res {
struct
nfs4_sequence_res
seq_res
;
};
struct
nfs4_layoutcommit_args
{
nfs4_stateid
stateid
;
__u64
lastbytewritten
;
struct
inode
*
inode
;
const
u32
*
bitmask
;
struct
nfs4_sequence_args
seq_args
;
};
struct
nfs4_layoutcommit_res
{
struct
nfs_fattr
*
fattr
;
const
struct
nfs_server
*
server
;
struct
nfs4_sequence_res
seq_res
;
};
struct
nfs4_layoutcommit_data
{
struct
rpc_task
task
;
struct
nfs_fattr
fattr
;
struct
pnfs_layout_segment
*
lseg
;
struct
rpc_cred
*
cred
;
struct
nfs4_layoutcommit_args
args
;
struct
nfs4_layoutcommit_res
res
;
};
/*
* Arguments to the open call.
*/
...
...
@@ -1077,6 +1102,7 @@ struct nfs_write_data {
struct
nfs_writeres
res
;
/* result struct */
struct
pnfs_layout_segment
*
lseg
;
struct
nfs_client
*
ds_clp
;
/* pNFS data server */
int
ds_commit_index
;
const
struct
rpc_call_ops
*
mds_ops
;
int
(
*
write_done_cb
)
(
struct
rpc_task
*
task
,
struct
nfs_write_data
*
data
);
#ifdef CONFIG_NFS_V4
...
...
net/sunrpc/xprtsock.c
View file @
0acd2201
...
...
@@ -710,6 +710,8 @@ static void xs_reset_transport(struct sock_xprt *transport)
if
(
sk
==
NULL
)
return
;
transport
->
srcport
=
0
;
write_lock_bh
(
&
sk
->
sk_callback_lock
);
transport
->
inet
=
NULL
;
transport
->
sock
=
NULL
;
...
...
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