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
36274526
Commit
36274526
authored
Jul 24, 2016
by
Trond Myklebust
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'writeback'
parents
7f94ed24
e033fb51
Changes
18
Hide whitespace changes
Inline
Side-by-side
Showing
18 changed files
with
438 additions
and
282 deletions
+438
-282
fs/nfs/Makefile
fs/nfs/Makefile
+1
-1
fs/nfs/dir.c
fs/nfs/dir.c
+31
-21
fs/nfs/direct.c
fs/nfs/direct.c
+32
-61
fs/nfs/file.c
fs/nfs/file.c
+27
-69
fs/nfs/filelayout/filelayout.c
fs/nfs/filelayout/filelayout.c
+13
-5
fs/nfs/flexfilelayout/flexfilelayout.c
fs/nfs/flexfilelayout/flexfilelayout.c
+13
-10
fs/nfs/inode.c
fs/nfs/inode.c
+67
-71
fs/nfs/internal.h
fs/nfs/internal.h
+40
-0
fs/nfs/io.c
fs/nfs/io.c
+147
-0
fs/nfs/nfs42proc.c
fs/nfs/nfs42proc.c
+18
-3
fs/nfs/nfs4file.c
fs/nfs/nfs4file.c
+2
-14
fs/nfs/nfs4xdr.c
fs/nfs/nfs4xdr.c
+8
-3
fs/nfs/nfstrace.h
fs/nfs/nfstrace.h
+0
-1
fs/nfs/pnfs.c
fs/nfs/pnfs.c
+4
-1
fs/nfs/pnfs.h
fs/nfs/pnfs.h
+7
-7
fs/nfs/pnfs_nfs.c
fs/nfs/pnfs_nfs.c
+7
-0
fs/nfs/write.c
fs/nfs/write.c
+20
-13
include/linux/nfs_fs.h
include/linux/nfs_fs.h
+1
-2
No files found.
fs/nfs/Makefile
View file @
36274526
...
...
@@ -6,7 +6,7 @@ obj-$(CONFIG_NFS_FS) += nfs.o
CFLAGS_nfstrace.o
+=
-I
$(src)
nfs-y
:=
client.o dir.o file.o getroot.o inode.o super.o
\
direct.o pagelist.o read.o symlink.o unlink.o
\
io.o
direct.o pagelist.o read.o symlink.o unlink.o
\
write.o namespace.o mount_clnt.o nfstrace.o
nfs-$(CONFIG_ROOT_NFS)
+=
nfsroot.o
nfs-$(CONFIG_SYSCTL)
+=
sysctl.o
...
...
fs/nfs/dir.c
View file @
36274526
...
...
@@ -2231,21 +2231,37 @@ static struct nfs_access_entry *nfs_access_search_rbtree(struct inode *inode, st
return
NULL
;
}
static
int
nfs_access_get_cached
(
struct
inode
*
inode
,
struct
rpc_cred
*
cred
,
struct
nfs_access_entry
*
res
)
static
int
nfs_access_get_cached
(
struct
inode
*
inode
,
struct
rpc_cred
*
cred
,
struct
nfs_access_entry
*
res
,
bool
may_block
)
{
struct
nfs_inode
*
nfsi
=
NFS_I
(
inode
);
struct
nfs_access_entry
*
cache
;
int
err
=
-
ENOENT
;
bool
retry
=
true
;
int
err
;
spin_lock
(
&
inode
->
i_lock
);
if
(
nfsi
->
cache_validity
&
NFS_INO_INVALID_ACCESS
)
goto
out_zap
;
cache
=
nfs_access_search_rbtree
(
inode
,
cred
);
if
(
cache
==
NULL
)
goto
out
;
if
(
!
nfs_have_delegated_attributes
(
inode
)
&&
!
time_in_range_open
(
jiffies
,
cache
->
jiffies
,
cache
->
jiffies
+
nfsi
->
attrtimeo
))
goto
out_stale
;
for
(;;)
{
if
(
nfsi
->
cache_validity
&
NFS_INO_INVALID_ACCESS
)
goto
out_zap
;
cache
=
nfs_access_search_rbtree
(
inode
,
cred
);
err
=
-
ENOENT
;
if
(
cache
==
NULL
)
goto
out
;
/* Found an entry, is our attribute cache valid? */
if
(
!
nfs_attribute_cache_expired
(
inode
)
&&
!
(
nfsi
->
cache_validity
&
NFS_INO_INVALID_ATTR
))
break
;
err
=
-
ECHILD
;
if
(
!
may_block
)
goto
out
;
if
(
!
retry
)
goto
out_zap
;
spin_unlock
(
&
inode
->
i_lock
);
err
=
__nfs_revalidate_inode
(
NFS_SERVER
(
inode
),
inode
);
if
(
err
)
return
err
;
spin_lock
(
&
inode
->
i_lock
);
retry
=
false
;
}
res
->
jiffies
=
cache
->
jiffies
;
res
->
cred
=
cache
->
cred
;
res
->
mask
=
cache
->
mask
;
...
...
@@ -2254,12 +2270,6 @@ static int nfs_access_get_cached(struct inode *inode, struct rpc_cred *cred, str
out:
spin_unlock
(
&
inode
->
i_lock
);
return
err
;
out_stale:
rb_erase
(
&
cache
->
rb_node
,
&
nfsi
->
access_cache
);
list_del
(
&
cache
->
lru
);
spin_unlock
(
&
inode
->
i_lock
);
nfs_access_free_entry
(
cache
);
return
-
ENOENT
;
out_zap:
spin_unlock
(
&
inode
->
i_lock
);
nfs_access_zap_cache
(
inode
);
...
...
@@ -2286,13 +2296,12 @@ static int nfs_access_get_cached_rcu(struct inode *inode, struct rpc_cred *cred,
cache
=
NULL
;
if
(
cache
==
NULL
)
goto
out
;
if
(
!
nfs_have_delegated_attributes
(
inode
)
&&
!
time_in_range_open
(
jiffies
,
cache
->
jiffies
,
cache
->
jiffies
+
nfsi
->
attrtimeo
)
)
err
=
nfs_revalidate_inode_rcu
(
NFS_SERVER
(
inode
),
inode
);
if
(
err
)
goto
out
;
res
->
jiffies
=
cache
->
jiffies
;
res
->
cred
=
cache
->
cred
;
res
->
mask
=
cache
->
mask
;
err
=
0
;
out:
rcu_read_unlock
();
return
err
;
...
...
@@ -2381,18 +2390,19 @@ EXPORT_SYMBOL_GPL(nfs_access_set_mask);
static
int
nfs_do_access
(
struct
inode
*
inode
,
struct
rpc_cred
*
cred
,
int
mask
)
{
struct
nfs_access_entry
cache
;
bool
may_block
=
(
mask
&
MAY_NOT_BLOCK
)
==
0
;
int
status
;
trace_nfs_access_enter
(
inode
);
status
=
nfs_access_get_cached_rcu
(
inode
,
cred
,
&
cache
);
if
(
status
!=
0
)
status
=
nfs_access_get_cached
(
inode
,
cred
,
&
cache
);
status
=
nfs_access_get_cached
(
inode
,
cred
,
&
cache
,
may_block
);
if
(
status
==
0
)
goto
out_cached
;
status
=
-
ECHILD
;
if
(
mask
&
MAY_NOT_BLOCK
)
if
(
!
may_block
)
goto
out
;
/* Be clever: ask server to check for all possible rights */
...
...
fs/nfs/direct.c
View file @
36274526
...
...
@@ -196,6 +196,12 @@ static void nfs_direct_set_hdr_verf(struct nfs_direct_req *dreq,
WARN_ON_ONCE
(
verfp
->
committed
<
0
);
}
static
int
nfs_direct_cmp_verf
(
const
struct
nfs_writeverf
*
v1
,
const
struct
nfs_writeverf
*
v2
)
{
return
nfs_write_verifier_cmp
(
&
v1
->
verifier
,
&
v2
->
verifier
);
}
/*
* nfs_direct_cmp_hdr_verf - compare verifier for pgio header
* @dreq - direct request possibly spanning multiple servers
...
...
@@ -215,7 +221,7 @@ static int nfs_direct_set_or_cmp_hdr_verf(struct nfs_direct_req *dreq,
nfs_direct_set_hdr_verf
(
dreq
,
hdr
);
return
0
;
}
return
memcmp
(
verfp
,
&
hdr
->
verf
,
sizeof
(
struct
nfs_writeverf
)
);
return
nfs_direct_cmp_verf
(
verfp
,
&
hdr
->
verf
);
}
/*
...
...
@@ -238,7 +244,7 @@ static int nfs_direct_cmp_commit_data_verf(struct nfs_direct_req *dreq,
if
(
verfp
->
committed
<
0
)
return
1
;
return
memcmp
(
verfp
,
&
data
->
verf
,
sizeof
(
struct
nfs_writeverf
)
);
return
nfs_direct_cmp_verf
(
verfp
,
&
data
->
verf
);
}
/**
...
...
@@ -368,22 +374,10 @@ static ssize_t nfs_direct_wait(struct nfs_direct_req *dreq)
* Synchronous I/O uses a stack-allocated iocb. Thus we can't trust
* the iocb is still valid here if this is a synchronous request.
*/
static
void
nfs_direct_complete
(
struct
nfs_direct_req
*
dreq
,
bool
write
)
static
void
nfs_direct_complete
(
struct
nfs_direct_req
*
dreq
)
{
struct
inode
*
inode
=
dreq
->
inode
;
if
(
dreq
->
iocb
&&
write
)
{
loff_t
pos
=
dreq
->
iocb
->
ki_pos
+
dreq
->
count
;
spin_lock
(
&
inode
->
i_lock
);
if
(
i_size_read
(
inode
)
<
pos
)
i_size_write
(
inode
,
pos
);
spin_unlock
(
&
inode
->
i_lock
);
}
if
(
write
)
nfs_zap_mapping
(
inode
,
inode
->
i_mapping
);
inode_dio_end
(
inode
);
if
(
dreq
->
iocb
)
{
...
...
@@ -438,7 +432,7 @@ static void nfs_direct_read_completion(struct nfs_pgio_header *hdr)
}
out_put:
if
(
put_dreq
(
dreq
))
nfs_direct_complete
(
dreq
,
false
);
nfs_direct_complete
(
dreq
);
hdr
->
release
(
hdr
);
}
...
...
@@ -544,7 +538,7 @@ static ssize_t nfs_direct_read_schedule_iovec(struct nfs_direct_req *dreq,
}
if
(
put_dreq
(
dreq
))
nfs_direct_complete
(
dreq
,
false
);
nfs_direct_complete
(
dreq
);
return
0
;
}
...
...
@@ -585,17 +579,12 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, struct iov_iter *iter)
if
(
!
count
)
goto
out
;
inode_lock
(
inode
);
result
=
nfs_sync_mapping
(
mapping
);
if
(
result
)
goto
out_unlock
;
task_io_account_read
(
count
);
result
=
-
ENOMEM
;
dreq
=
nfs_direct_req_alloc
();
if
(
dreq
==
NULL
)
goto
out
_unlock
;
goto
out
;
dreq
->
inode
=
inode
;
dreq
->
bytes_left
=
dreq
->
max_count
=
count
;
...
...
@@ -610,10 +599,12 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, struct iov_iter *iter)
if
(
!
is_sync_kiocb
(
iocb
))
dreq
->
iocb
=
iocb
;
nfs_start_io_direct
(
inode
);
NFS_I
(
inode
)
->
read_io
+=
count
;
result
=
nfs_direct_read_schedule_iovec
(
dreq
,
iter
,
iocb
->
ki_pos
);
inode_unlock
(
inode
);
nfs_end_io_direct
(
inode
);
if
(
!
result
)
{
result
=
nfs_direct_wait
(
dreq
);
...
...
@@ -621,13 +612,8 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, struct iov_iter *iter)
iocb
->
ki_pos
+=
result
;
}
nfs_direct_req_release
(
dreq
);
return
result
;
out_release:
nfs_direct_req_release
(
dreq
);
out_unlock:
inode_unlock
(
inode
);
out:
return
result
;
}
...
...
@@ -659,6 +645,8 @@ static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq)
nfs_direct_write_scan_commit_list
(
dreq
->
inode
,
&
reqs
,
&
cinfo
);
dreq
->
count
=
0
;
dreq
->
verf
.
committed
=
NFS_INVALID_STABLE_HOW
;
nfs_clear_pnfs_ds_commit_verifiers
(
&
dreq
->
ds_cinfo
);
for
(
i
=
0
;
i
<
dreq
->
mirror_count
;
i
++
)
dreq
->
mirrors
[
i
].
count
=
0
;
get_dreq
(
dreq
);
...
...
@@ -777,7 +765,8 @@ static void nfs_direct_write_schedule_work(struct work_struct *work)
nfs_direct_write_reschedule
(
dreq
);
break
;
default:
nfs_direct_complete
(
dreq
,
true
);
nfs_zap_mapping
(
dreq
->
inode
,
dreq
->
inode
->
i_mapping
);
nfs_direct_complete
(
dreq
);
}
}
...
...
@@ -993,6 +982,7 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq,
ssize_t
nfs_file_direct_write
(
struct
kiocb
*
iocb
,
struct
iov_iter
*
iter
)
{
ssize_t
result
=
-
EINVAL
;
size_t
count
;
struct
file
*
file
=
iocb
->
ki_filp
;
struct
address_space
*
mapping
=
file
->
f_mapping
;
struct
inode
*
inode
=
mapping
->
host
;
...
...
@@ -1003,34 +993,24 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter)
dfprintk
(
FILE
,
"NFS: direct write(%pD2, %zd@%Ld)
\n
"
,
file
,
iov_iter_count
(
iter
),
(
long
long
)
iocb
->
ki_pos
);
nfs_add_stats
(
mapping
->
host
,
NFSIOS_DIRECTWRITTENBYTES
,
iov_iter_count
(
iter
));
result
=
generic_write_checks
(
iocb
,
iter
);
if
(
result
<=
0
)
return
result
;
count
=
result
;
nfs_add_stats
(
mapping
->
host
,
NFSIOS_DIRECTWRITTENBYTES
,
count
);
pos
=
iocb
->
ki_pos
;
end
=
(
pos
+
iov_iter_count
(
iter
)
-
1
)
>>
PAGE_SHIFT
;
inode_lock
(
inode
);
result
=
nfs_sync_mapping
(
mapping
);
if
(
result
)
goto
out_unlock
;
if
(
mapping
->
nrpages
)
{
result
=
invalidate_inode_pages2_range
(
mapping
,
pos
>>
PAGE_SHIFT
,
end
);
if
(
result
)
goto
out_unlock
;
}
task_io_account_write
(
iov_iter_count
(
iter
));
task_io_account_write
(
count
);
result
=
-
ENOMEM
;
dreq
=
nfs_direct_req_alloc
();
if
(
!
dreq
)
goto
out
_unlock
;
goto
out
;
dreq
->
inode
=
inode
;
dreq
->
bytes_left
=
dreq
->
max_count
=
iov_iter_count
(
iter
)
;
dreq
->
bytes_left
=
dreq
->
max_count
=
count
;
dreq
->
io_start
=
pos
;
dreq
->
ctx
=
get_nfs_open_context
(
nfs_file_open_context
(
iocb
->
ki_filp
));
l_ctx
=
nfs_get_lock_context
(
dreq
->
ctx
);
...
...
@@ -1042,6 +1022,8 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter)
if
(
!
is_sync_kiocb
(
iocb
))
dreq
->
iocb
=
iocb
;
nfs_start_io_direct
(
inode
);
result
=
nfs_direct_write_schedule_iovec
(
dreq
,
iter
,
pos
);
if
(
mapping
->
nrpages
)
{
...
...
@@ -1049,30 +1031,19 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter)
pos
>>
PAGE_SHIFT
,
end
);
}
inode_unlock
(
inode
);
nfs_end_io_direct
(
inode
);
if
(
!
result
)
{
result
=
nfs_direct_wait
(
dreq
);
if
(
result
>
0
)
{
struct
inode
*
inode
=
mapping
->
host
;
iocb
->
ki_pos
=
pos
+
result
;
spin_lock
(
&
inode
->
i_lock
);
if
(
i_size_read
(
inode
)
<
iocb
->
ki_pos
)
i_size_write
(
inode
,
iocb
->
ki_pos
);
spin_unlock
(
&
inode
->
i_lock
);
/* XXX: should check the generic_write_sync retval */
generic_write_sync
(
iocb
,
result
);
}
}
nfs_direct_req_release
(
dreq
);
return
result
;
out_release:
nfs_direct_req_release
(
dreq
);
out_unlock:
inode_unlock
(
inode
);
out:
return
result
;
}
...
...
fs/nfs/file.c
View file @
36274526
...
...
@@ -170,12 +170,14 @@ nfs_file_read(struct kiocb *iocb, struct iov_iter *to)
iocb
->
ki_filp
,
iov_iter_count
(
to
),
(
unsigned
long
)
iocb
->
ki_pos
);
result
=
nfs_revalidate_mapping_protected
(
inode
,
iocb
->
ki_filp
->
f_mapping
);
nfs_start_io_read
(
inode
);
result
=
nfs_revalidate_mapping
(
inode
,
iocb
->
ki_filp
->
f_mapping
);
if
(
!
result
)
{
result
=
generic_file_read_iter
(
iocb
,
to
);
if
(
result
>
0
)
nfs_add_stats
(
inode
,
NFSIOS_NORMALREADBYTES
,
result
);
}
nfs_end_io_read
(
inode
);
return
result
;
}
EXPORT_SYMBOL_GPL
(
nfs_file_read
);
...
...
@@ -191,12 +193,14 @@ nfs_file_splice_read(struct file *filp, loff_t *ppos,
dprintk
(
"NFS: splice_read(%pD2, %lu@%Lu)
\n
"
,
filp
,
(
unsigned
long
)
count
,
(
unsigned
long
long
)
*
ppos
);
res
=
nfs_revalidate_mapping_protected
(
inode
,
filp
->
f_mapping
);
nfs_start_io_read
(
inode
);
res
=
nfs_revalidate_mapping
(
inode
,
filp
->
f_mapping
);
if
(
!
res
)
{
res
=
generic_file_splice_read
(
filp
,
ppos
,
pipe
,
count
,
flags
);
if
(
res
>
0
)
nfs_add_stats
(
inode
,
NFSIOS_NORMALREADBYTES
,
res
);
}
nfs_end_io_read
(
inode
);
return
res
;
}
EXPORT_SYMBOL_GPL
(
nfs_file_splice_read
);
...
...
@@ -272,16 +276,13 @@ nfs_file_fsync(struct file *file, loff_t start, loff_t end, int datasync)
trace_nfs_fsync_enter
(
inode
);
inode_dio_wait
(
inode
);
do
{
ret
=
filemap_write_and_wait_range
(
inode
->
i_mapping
,
start
,
end
);
if
(
ret
!=
0
)
break
;
inode_lock
(
inode
);
ret
=
nfs_file_fsync_commit
(
file
,
start
,
end
,
datasync
);
if
(
!
ret
)
ret
=
pnfs_sync_inode
(
inode
,
!!
datasync
);
inode_unlock
(
inode
);
/*
* If nfs_file_fsync_commit detected a server reboot, then
* resend all dirty pages that might have been covered by
...
...
@@ -359,19 +360,6 @@ static int nfs_write_begin(struct file *file, struct address_space *mapping,
file
,
mapping
->
host
->
i_ino
,
len
,
(
long
long
)
pos
);
start:
/*
* Prevent starvation issues if someone is doing a consistency
* sync-to-disk
*/
ret
=
wait_on_bit_action
(
&
NFS_I
(
mapping
->
host
)
->
flags
,
NFS_INO_FLUSHING
,
nfs_wait_bit_killable
,
TASK_KILLABLE
);
if
(
ret
)
return
ret
;
/*
* Wait for O_DIRECT to complete
*/
inode_dio_wait
(
mapping
->
host
);
page
=
grab_cache_page_write_begin
(
mapping
,
index
,
flags
);
if
(
!
page
)
return
-
ENOMEM
;
...
...
@@ -470,31 +458,8 @@ static void nfs_invalidate_page(struct page *page, unsigned int offset,
*/
static
int
nfs_release_page
(
struct
page
*
page
,
gfp_t
gfp
)
{
struct
address_space
*
mapping
=
page
->
mapping
;
dfprintk
(
PAGECACHE
,
"NFS: release_page(%p)
\n
"
,
page
);
/* Always try to initiate a 'commit' if relevant, but only
* wait for it if the caller allows blocking. Even then,
* only wait 1 second and only if the 'bdi' is not congested.
* Waiting indefinitely can cause deadlocks when the NFS
* server is on this machine, when a new TCP connection is
* needed and in other rare cases. There is no particular
* need to wait extensively here. A short wait has the
* benefit that someone else can worry about the freezer.
*/
if
(
mapping
)
{
struct
nfs_server
*
nfss
=
NFS_SERVER
(
mapping
->
host
);
nfs_commit_inode
(
mapping
->
host
,
0
);
if
(
gfpflags_allow_blocking
(
gfp
)
&&
!
bdi_write_congested
(
&
nfss
->
backing_dev_info
))
{
wait_on_page_bit_killable_timeout
(
page
,
PG_private
,
HZ
);
if
(
PagePrivate
(
page
))
set_bdi_congested
(
&
nfss
->
backing_dev_info
,
BLK_RW_ASYNC
);
}
}
/* If PagePrivate() is set, then the page is not freeable */
if
(
PagePrivate
(
page
))
return
0
;
...
...
@@ -604,6 +569,8 @@ static int nfs_vm_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
filp
,
filp
->
f_mapping
->
host
->
i_ino
,
(
long
long
)
page_offset
(
page
));
sb_start_pagefault
(
inode
->
i_sb
);
/* make sure the cache has finished storing the page */
nfs_fscache_wait_on_page_write
(
NFS_I
(
inode
),
page
);
...
...
@@ -630,6 +597,7 @@ static int nfs_vm_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
out_unlock:
unlock_page
(
page
);
out:
sb_end_pagefault
(
inode
->
i_sb
);
return
ret
;
}
...
...
@@ -656,23 +624,17 @@ ssize_t nfs_file_write(struct kiocb *iocb, struct iov_iter *from)
struct
inode
*
inode
=
file_inode
(
file
);
unsigned
long
written
=
0
;
ssize_t
result
;
size_t
count
=
iov_iter_count
(
from
);
result
=
nfs_key_timeout_notify
(
file
,
inode
);
if
(
result
)
return
result
;
if
(
iocb
->
ki_flags
&
IOCB_DIRECT
)
{
result
=
generic_write_checks
(
iocb
,
from
);
if
(
result
<=
0
)
return
result
;
if
(
iocb
->
ki_flags
&
IOCB_DIRECT
)
return
nfs_file_direct_write
(
iocb
,
from
);
}
dprintk
(
"NFS: write(%pD2, %zu@%Ld)
\n
"
,
file
,
count
,
(
long
long
)
iocb
->
ki_pos
);
file
,
iov_iter_count
(
from
)
,
(
long
long
)
iocb
->
ki_pos
);
result
=
-
EBUSY
;
if
(
IS_SWAPFILE
(
inode
))
goto
out_swapfile
;
/*
...
...
@@ -684,28 +646,33 @@ ssize_t nfs_file_write(struct kiocb *iocb, struct iov_iter *from)
goto
out
;
}
result
=
count
;
if
(
!
count
)
nfs_start_io_write
(
inode
);
result
=
generic_write_checks
(
iocb
,
from
);
if
(
result
>
0
)
{
current
->
backing_dev_info
=
inode_to_bdi
(
inode
);
result
=
generic_perform_write
(
file
,
from
,
iocb
->
ki_pos
);
current
->
backing_dev_info
=
NULL
;
}
nfs_end_io_write
(
inode
);
if
(
result
<=
0
)
goto
out
;
result
=
generic_file_write_iter
(
iocb
,
from
);
if
(
result
>
0
)
written
=
result
;
written
=
generic_write_sync
(
iocb
,
result
);
iocb
->
ki_pos
+=
written
;
/* Return error values */
if
(
result
>=
0
&&
nfs_need_check_write
(
file
,
inode
))
{
if
(
nfs_need_check_write
(
file
,
inode
))
{
int
err
=
vfs_fsync
(
file
,
0
);
if
(
err
<
0
)
result
=
err
;
}
if
(
result
>
0
)
nfs_add_stats
(
inode
,
NFSIOS_NORMALWRITTENBYTES
,
written
);
nfs_add_stats
(
inode
,
NFSIOS_NORMALWRITTENBYTES
,
written
);
out:
return
result
;
out_swapfile:
printk
(
KERN_INFO
"NFS: attempt to write to active swap file!
\n
"
);
goto
out
;
return
-
EBUSY
;
}
EXPORT_SYMBOL_GPL
(
nfs_file_write
);
...
...
@@ -779,11 +746,6 @@ do_unlk(struct file *filp, int cmd, struct file_lock *fl, int is_local)
return
status
;
}
static
int
is_time_granular
(
struct
timespec
*
ts
)
{
return
((
ts
->
tv_sec
==
0
)
&&
(
ts
->
tv_nsec
<=
1000
));
}
static
int
do_setlk
(
struct
file
*
filp
,
int
cmd
,
struct
file_lock
*
fl
,
int
is_local
)
{
...
...
@@ -817,12 +779,8 @@ do_setlk(struct file *filp, int cmd, struct file_lock *fl, int is_local)
* This makes locking act as a cache coherency point.
*/
nfs_sync_mapping
(
filp
->
f_mapping
);
if
(
!
NFS_PROTO
(
inode
)
->
have_delegation
(
inode
,
FMODE_READ
))
{
if
(
is_time_granular
(
&
NFS_SERVER
(
inode
)
->
time_delta
))
__nfs_revalidate_inode
(
NFS_SERVER
(
inode
),
inode
);
else
nfs_zap_caches
(
inode
);
}
if
(
!
NFS_PROTO
(
inode
)
->
have_delegation
(
inode
,
FMODE_READ
))
nfs_zap_mapping
(
inode
,
filp
->
f_mapping
);
out:
return
status
;
}
...
...
fs/nfs/filelayout/filelayout.c
View file @
36274526
...
...
@@ -255,13 +255,16 @@ static int filelayout_read_done_cb(struct rpc_task *task,
static
void
filelayout_set_layoutcommit
(
struct
nfs_pgio_header
*
hdr
)
{
loff_t
end_offs
=
0
;
if
(
FILELAYOUT_LSEG
(
hdr
->
lseg
)
->
commit_through_mds
||
hdr
->
res
.
verf
->
committed
!=
NFS_DATA
_SYNC
)
hdr
->
res
.
verf
->
committed
==
NFS_FILE
_SYNC
)
return
;
if
(
hdr
->
res
.
verf
->
committed
==
NFS_DATA_SYNC
)
end_offs
=
hdr
->
mds_offset
+
(
loff_t
)
hdr
->
res
.
count
;
pnfs_set_layoutcommit
(
hdr
->
inode
,
hdr
->
lseg
,
hdr
->
mds_offset
+
hdr
->
res
.
count
);
/* Note: if the write is unstable, don't set end_offs until commit */
pnfs_set_layoutcommit
(
hdr
->
inode
,
hdr
->
lseg
,
end_offs
);
dprintk
(
"%s inode %lu pls_end_pos %lu
\n
"
,
__func__
,
hdr
->
inode
->
i_ino
,
(
unsigned
long
)
NFS_I
(
hdr
->
inode
)
->
layout
->
plh_lwb
);
}
...
...
@@ -354,6 +357,12 @@ static int filelayout_write_done_cb(struct rpc_task *task,
}
filelayout_set_layoutcommit
(
hdr
);
/* zero out the fattr */
hdr
->
fattr
.
valid
=
0
;
if
(
task
->
tk_status
>=
0
)
nfs_writeback_update_inode
(
hdr
);
return
0
;
}
...
...
@@ -375,8 +384,7 @@ static int filelayout_commit_done_cb(struct rpc_task *task,
return
-
EAGAIN
;
}
if
(
data
->
verf
.
committed
==
NFS_UNSTABLE
)
pnfs_set_layoutcommit
(
data
->
inode
,
data
->
lseg
,
data
->
lwb
);
pnfs_set_layoutcommit
(
data
->
inode
,
data
->
lseg
,
data
->
lwb
);
return
0
;
}
...
...
fs/nfs/flexfilelayout/flexfilelayout.c
View file @
36274526
...
...
@@ -1325,15 +1325,16 @@ ff_layout_need_layoutcommit(struct pnfs_layout_segment *lseg)
* we always send layoutcommit after DS writes.
*/
static
void
ff_layout_set_layoutcommit
(
struct
nfs_pgio_header
*
hdr
)
ff_layout_set_layoutcommit
(
struct
inode
*
inode
,
struct
pnfs_layout_segment
*
lseg
,
loff_t
end_offset
)
{
if
(
!
ff_layout_need_layoutcommit
(
hdr
->
lseg
))
if
(
!
ff_layout_need_layoutcommit
(
lseg
))
return
;
pnfs_set_layoutcommit
(
hdr
->
inode
,
hdr
->
lseg
,
hdr
->
mds_offset
+
hdr
->
res
.
count
);
dprintk
(
"%s inode %lu pls_end_pos %lu
\n
"
,
__func__
,
hdr
->
inode
->
i_ino
,
(
unsigned
long
)
NFS_I
(
hdr
->
inode
)
->
layout
->
plh_lwb
);
pnfs_set_layoutcommit
(
inode
,
lseg
,
end_offset
);
dprintk
(
"%s inode %lu pls_end_pos %llu
\n
"
,
__func__
,
inode
->
i_ino
,
(
unsigned
long
long
)
NFS_I
(
inode
)
->
layout
->
plh_lwb
);
}
static
bool
...
...
@@ -1469,6 +1470,7 @@ static void ff_layout_read_release(void *data)
static
int
ff_layout_write_done_cb
(
struct
rpc_task
*
task
,
struct
nfs_pgio_header
*
hdr
)
{
loff_t
end_offs
=
0
;
int
err
;
trace_nfs4_pnfs_write
(
hdr
,
task
->
tk_status
);
...
...
@@ -1494,7 +1496,10 @@ static int ff_layout_write_done_cb(struct rpc_task *task,
if
(
hdr
->
res
.
verf
->
committed
==
NFS_FILE_SYNC
||
hdr
->
res
.
verf
->
committed
==
NFS_DATA_SYNC
)
ff_layout_set_layoutcommit
(
hdr
);
end_offs
=
hdr
->
mds_offset
+
(
loff_t
)
hdr
->
res
.
count
;
/* Note: if the write is unstable, don't set end_offs until commit */
ff_layout_set_layoutcommit
(
hdr
->
inode
,
hdr
->
lseg
,
end_offs
);
/* zero out fattr since we don't care DS attr at all */
hdr
->
fattr
.
valid
=
0
;
...
...
@@ -1530,9 +1535,7 @@ static int ff_layout_commit_done_cb(struct rpc_task *task,
return
-
EAGAIN
;
}
if
(
data
->
verf
.
committed
==
NFS_UNSTABLE
&&
ff_layout_need_layoutcommit
(
data
->
lseg
))
pnfs_set_layoutcommit
(
data
->
inode
,
data
->
lseg
,
data
->
lwb
);
ff_layout_set_layoutcommit
(
data
->
inode
,
data
->
lseg
,
data
->
lwb
);
return
0
;
}
...
...
fs/nfs/inode.c
View file @
36274526
...
...
@@ -662,9 +662,7 @@ int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
trace_nfs_getattr_enter
(
inode
);
/* Flush out writes to the server in order to update c/mtime. */
if
(
S_ISREG
(
inode
->
i_mode
))
{
inode_lock
(
inode
);
err
=
nfs_sync_inode
(
inode
);
inode_unlock
(
inode
);
err
=
filemap_write_and_wait
(
inode
->
i_mapping
);
if
(
err
)
goto
out
;
}
...
...
@@ -879,7 +877,10 @@ void nfs_inode_attach_open_context(struct nfs_open_context *ctx)
struct
nfs_inode
*
nfsi
=
NFS_I
(
inode
);
spin_lock
(
&
inode
->
i_lock
);
list_add
(
&
ctx
->
list
,
&
nfsi
->
open_files
);
if
(
ctx
->
mode
&
FMODE_WRITE
)
list_add
(
&
ctx
->
list
,
&
nfsi
->
open_files
);
else
list_add_tail
(
&
ctx
->
list
,
&
nfsi
->
open_files
);
spin_unlock
(
&
inode
->
i_lock
);
}
EXPORT_SYMBOL_GPL
(
nfs_inode_attach_open_context
);
...
...
@@ -972,6 +973,13 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
if
(
NFS_STALE
(
inode
))
goto
out
;
/* pNFS: Attributes aren't updated until we layoutcommit */
if
(
S_ISREG
(
inode
->
i_mode
))
{
status
=
pnfs_sync_inode
(
inode
,
false
);
if
(
status
)
goto
out
;
}
status
=
-
ENOMEM
;
fattr
=
nfs_alloc_fattr
();
if
(
fattr
==
NULL
)
...
...
@@ -1122,14 +1130,12 @@ int nfs_revalidate_mapping_rcu(struct inode *inode)
}
/**
*
__
nfs_revalidate_mapping - Revalidate the pagecache
* nfs_revalidate_mapping - Revalidate the pagecache
* @inode - pointer to host inode
* @mapping - pointer to mapping
* @may_lock - take inode->i_mutex?
*/
static
int
__nfs_revalidate_mapping
(
struct
inode
*
inode
,
struct
address_space
*
mapping
,
bool
may_lock
)
int
nfs_revalidate_mapping
(
struct
inode
*
inode
,
struct
address_space
*
mapping
)
{
struct
nfs_inode
*
nfsi
=
NFS_I
(
inode
);
unsigned
long
*
bitlock
=
&
nfsi
->
flags
;
...
...
@@ -1178,12 +1184,7 @@ static int __nfs_revalidate_mapping(struct inode *inode,
nfsi
->
cache_validity
&=
~
NFS_INO_INVALID_DATA
;
spin_unlock
(
&
inode
->
i_lock
);
trace_nfs_invalidate_mapping_enter
(
inode
);
if
(
may_lock
)
{
inode_lock
(
inode
);
ret
=
nfs_invalidate_mapping
(
inode
,
mapping
);
inode_unlock
(
inode
);
}
else
ret
=
nfs_invalidate_mapping
(
inode
,
mapping
);
ret
=
nfs_invalidate_mapping
(
inode
,
mapping
);
trace_nfs_invalidate_mapping_exit
(
inode
,
ret
);
clear_bit_unlock
(
NFS_INO_INVALIDATING
,
bitlock
);
...
...
@@ -1193,27 +1194,28 @@ static int __nfs_revalidate_mapping(struct inode *inode,
return
ret
;
}
/**
* nfs_revalidate_mapping - Revalidate the pagecache
* @inode - pointer to host inode
* @mapping - pointer to mapping
*/
int
nfs_revalidate_mapping
(
struct
inode
*
inode
,
struct
address_space
*
mapping
)
static
bool
nfs_file_has_writers
(
struct
nfs_inode
*
nfsi
)
{
return
__nfs_revalidate_mapping
(
inode
,
mapping
,
false
);
struct
inode
*
inode
=
&
nfsi
->
vfs_inode
;
assert_spin_locked
(
&
inode
->
i_lock
);
if
(
!
S_ISREG
(
inode
->
i_mode
))
return
false
;
if
(
list_empty
(
&
nfsi
->
open_files
))
return
false
;
/* Note: This relies on nfsi->open_files being ordered with writers
* being placed at the head of the list.
* See nfs_inode_attach_open_context()
*/
return
(
list_first_entry
(
&
nfsi
->
open_files
,
struct
nfs_open_context
,
list
)
->
mode
&
FMODE_WRITE
)
==
FMODE_WRITE
;
}
/**
* nfs_revalidate_mapping_protected - Revalidate the pagecache
* @inode - pointer to host inode
* @mapping - pointer to mapping
*
* Differs from nfs_revalidate_mapping() in that it grabs the inode->i_mutex
* while invalidating the mapping.
*/
int
nfs_revalidate_mapping_protected
(
struct
inode
*
inode
,
struct
address_space
*
mapping
)
static
bool
nfs_file_has_buffered_writers
(
struct
nfs_inode
*
nfsi
)
{
return
__nfs_revalidate_mapping
(
inode
,
mapping
,
true
);
return
nfs_file_has_writers
(
nfsi
)
&&
nfs_file_io_is_buffered
(
nfsi
);
}
static
unsigned
long
nfs_wcc_update_inode
(
struct
inode
*
inode
,
struct
nfs_fattr
*
fattr
)
...
...
@@ -1280,22 +1282,24 @@ static int nfs_check_inode_attributes(struct inode *inode, struct nfs_fattr *fat
if
((
fattr
->
valid
&
NFS_ATTR_FATTR_TYPE
)
&&
(
inode
->
i_mode
&
S_IFMT
)
!=
(
fattr
->
mode
&
S_IFMT
))
return
-
EIO
;
if
((
fattr
->
valid
&
NFS_ATTR_FATTR_CHANGE
)
!=
0
&&
inode
->
i_version
!=
fattr
->
change_attr
)
invalid
|=
NFS_INO_INVALID_ATTR
|
NFS_INO_REVAL_PAGECACHE
;
if
(
!
nfs_file_has_buffered_writers
(
nfsi
))
{
/* Verify a few of the more important attributes */
if
((
fattr
->
valid
&
NFS_ATTR_FATTR_CHANGE
)
!=
0
&&
inode
->
i_version
!=
fattr
->
change_attr
)
invalid
|=
NFS_INO_INVALID_ATTR
|
NFS_INO_REVAL_PAGECACHE
;
/* Verify a few of the more important attributes */
if
((
fattr
->
valid
&
NFS_ATTR_FATTR_MTIME
)
&&
!
timespec_equal
(
&
inode
->
i_mtime
,
&
fattr
->
mtime
))
invalid
|=
NFS_INO_INVALID_ATTR
;
if
((
fattr
->
valid
&
NFS_ATTR_FATTR_MTIME
)
&&
!
timespec_equal
(
&
inode
->
i_mtime
,
&
fattr
->
mtime
))
invalid
|=
NFS_INO_INVALID_ATTR
;
if
(
fattr
->
valid
&
NFS_ATTR_FATTR_SIZE
)
{
cur_size
=
i_size_read
(
inode
);
new_isize
=
nfs_size_to_loff_t
(
fattr
->
size
);
if
(
cur_size
!=
new_isize
)
invalid
|=
NFS_INO_INVALID_ATTR
|
NFS_INO_REVAL_PAGECACHE
;
if
((
fattr
->
valid
&
NFS_ATTR_FATTR_CTIME
)
&&
!
timespec_equal
(
&
inode
->
i_ctime
,
&
fattr
->
ctime
))
invalid
|=
NFS_INO_INVALID_ATTR
;
if
(
fattr
->
valid
&
NFS_ATTR_FATTR_SIZE
)
{
cur_size
=
i_size_read
(
inode
);
new_isize
=
nfs_size_to_loff_t
(
fattr
->
size
);
if
(
cur_size
!=
new_isize
)
invalid
|=
NFS_INO_INVALID_ATTR
|
NFS_INO_REVAL_PAGECACHE
;
}
}
if
(
nfsi
->
nrequests
!=
0
)
invalid
&=
~
NFS_INO_REVAL_PAGECACHE
;
/* Have any file permissions changed? */
if
((
fattr
->
valid
&
NFS_ATTR_FATTR_MODE
)
&&
(
inode
->
i_mode
&
S_IALLUGO
)
!=
(
fattr
->
mode
&
S_IALLUGO
))
...
...
@@ -1470,28 +1474,12 @@ static int nfs_inode_attrs_need_update(const struct inode *inode, const struct n
((
long
)
nfsi
->
attr_gencount
-
(
long
)
nfs_read_attr_generation_counter
()
>
0
);
}
/*
* Don't trust the change_attribute, mtime, ctime or size if
* a pnfs LAYOUTCOMMIT is outstanding
*/
static
void
nfs_inode_attrs_handle_layoutcommit
(
struct
inode
*
inode
,
struct
nfs_fattr
*
fattr
)
{
if
(
pnfs_layoutcommit_outstanding
(
inode
))
fattr
->
valid
&=
~
(
NFS_ATTR_FATTR_CHANGE
|
NFS_ATTR_FATTR_MTIME
|
NFS_ATTR_FATTR_CTIME
|
NFS_ATTR_FATTR_SIZE
);
}
static
int
nfs_refresh_inode_locked
(
struct
inode
*
inode
,
struct
nfs_fattr
*
fattr
)
{
int
ret
;
trace_nfs_refresh_inode_enter
(
inode
);
nfs_inode_attrs_handle_layoutcommit
(
inode
,
fattr
);
if
(
nfs_inode_attrs_need_update
(
inode
,
fattr
))
ret
=
nfs_update_inode
(
inode
,
fattr
);
else
...
...
@@ -1527,7 +1515,7 @@ EXPORT_SYMBOL_GPL(nfs_refresh_inode);
static
int
nfs_post_op_update_inode_locked
(
struct
inode
*
inode
,
struct
nfs_fattr
*
fattr
)
{
unsigned
long
invalid
=
NFS_INO_INVALID_ATTR
|
NFS_INO_REVAL_PAGECACHE
;
unsigned
long
invalid
=
NFS_INO_INVALID_ATTR
;
/*
* Don't revalidate the pagecache if we hold a delegation, but do
...
...
@@ -1676,7 +1664,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
unsigned
long
invalid
=
0
;
unsigned
long
now
=
jiffies
;
unsigned
long
save_cache_validity
;
bool
cache_revalidated
=
true
;
bool
have_writers
=
nfs_file_has_buffered_writers
(
nfsi
);
bool
cache_revalidated
;
dfprintk
(
VFS
,
"NFS: %s(%s/%lu fh_crc=0x%08x ct=%d info=0x%x)
\n
"
,
__func__
,
inode
->
i_sb
->
s_id
,
inode
->
i_ino
,
...
...
@@ -1725,17 +1714,23 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
/* Do atomic weak cache consistency updates */
invalid
|=
nfs_wcc_update_inode
(
inode
,
fattr
);
cache_revalidated
=
!
pnfs_layoutcommit_outstanding
(
inode
);
/* More cache consistency checks */
if
(
fattr
->
valid
&
NFS_ATTR_FATTR_CHANGE
)
{
if
(
inode
->
i_version
!=
fattr
->
change_attr
)
{
dprintk
(
"NFS: change_attr change on server for file %s/%ld
\n
"
,
inode
->
i_sb
->
s_id
,
inode
->
i_ino
);
invalid
|=
NFS_INO_INVALID_ATTR
|
NFS_INO_INVALID_DATA
|
NFS_INO_INVALID_ACCESS
|
NFS_INO_INVALID_ACL
;
if
(
S_ISDIR
(
inode
->
i_mode
))
nfs_force_lookup_revalidate
(
inode
);
/* Could it be a race with writeback? */
if
(
!
have_writers
)
{
invalid
|=
NFS_INO_INVALID_ATTR
|
NFS_INO_INVALID_DATA
|
NFS_INO_INVALID_ACCESS
|
NFS_INO_INVALID_ACL
;
if
(
S_ISDIR
(
inode
->
i_mode
))
nfs_force_lookup_revalidate
(
inode
);
}
inode
->
i_version
=
fattr
->
change_attr
;
}
}
else
{
...
...
@@ -1768,9 +1763,10 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
if
(
new_isize
!=
cur_isize
)
{
/* Do we perhaps have any outstanding writes, or has
* the file grown beyond our last write? */
if
(
(
nfsi
->
nrequests
==
0
)
||
new_isize
>
cur_isize
)
{
if
(
nfsi
->
nrequests
==
0
||
new_isize
>
cur_isize
)
{
i_size_write
(
inode
,
new_isize
);
invalid
|=
NFS_INO_INVALID_ATTR
|
NFS_INO_INVALID_DATA
;
if
(
!
have_writers
)
invalid
|=
NFS_INO_INVALID_ATTR
|
NFS_INO_INVALID_DATA
;
}
dprintk
(
"NFS: isize change on server for file %s/%ld "
"(%Ld to %Ld)
\n
"
,
...
...
fs/nfs/internal.h
View file @
36274526
...
...
@@ -412,6 +412,19 @@ extern void __exit unregister_nfs_fs(void);
extern
bool
nfs_sb_active
(
struct
super_block
*
sb
);
extern
void
nfs_sb_deactive
(
struct
super_block
*
sb
);
/* io.c */
extern
void
nfs_start_io_read
(
struct
inode
*
inode
);
extern
void
nfs_end_io_read
(
struct
inode
*
inode
);
extern
void
nfs_start_io_write
(
struct
inode
*
inode
);
extern
void
nfs_end_io_write
(
struct
inode
*
inode
);
extern
void
nfs_start_io_direct
(
struct
inode
*
inode
);
extern
void
nfs_end_io_direct
(
struct
inode
*
inode
);
static
inline
bool
nfs_file_io_is_buffered
(
struct
nfs_inode
*
nfsi
)
{
return
test_bit
(
NFS_INO_ODIRECT
,
&
nfsi
->
flags
)
==
0
;
}
/* namespace.c */
#define NFS_PATH_CANONICAL 1
extern
char
*
nfs_path
(
char
**
p
,
struct
dentry
*
dentry
,
...
...
@@ -500,6 +513,26 @@ int nfs_key_timeout_notify(struct file *filp, struct inode *inode);
bool
nfs_ctx_key_to_expire
(
struct
nfs_open_context
*
ctx
,
struct
inode
*
inode
);
void
nfs_pageio_stop_mirroring
(
struct
nfs_pageio_descriptor
*
pgio
);
int
nfs_filemap_write_and_wait_range
(
struct
address_space
*
mapping
,
loff_t
lstart
,
loff_t
lend
);
#ifdef CONFIG_NFS_V4_1
static
inline
void
nfs_clear_pnfs_ds_commit_verifiers
(
struct
pnfs_ds_commit_info
*
cinfo
)
{
int
i
;
for
(
i
=
0
;
i
<
cinfo
->
nbuckets
;
i
++
)
cinfo
->
buckets
[
i
].
direct_verf
.
committed
=
NFS_INVALID_STABLE_HOW
;
}
#else
static
inline
void
nfs_clear_pnfs_ds_commit_verifiers
(
struct
pnfs_ds_commit_info
*
cinfo
)
{
}
#endif
#ifdef CONFIG_MIGRATION
extern
int
nfs_migrate_page
(
struct
address_space
*
,
struct
page
*
,
struct
page
*
,
enum
migrate_mode
);
...
...
@@ -507,6 +540,13 @@ extern int nfs_migrate_page(struct address_space *,
#define nfs_migrate_page NULL
#endif
static
inline
int
nfs_write_verifier_cmp
(
const
struct
nfs_write_verifier
*
v1
,
const
struct
nfs_write_verifier
*
v2
)
{
return
memcmp
(
v1
->
data
,
v2
->
data
,
sizeof
(
v1
->
data
));
}
/* unlink.c */
extern
struct
rpc_task
*
nfs_async_rename
(
struct
inode
*
old_dir
,
struct
inode
*
new_dir
,
...
...
fs/nfs/io.c
0 → 100644
View file @
36274526
/*
* Copyright (c) 2016 Trond Myklebust
*
* I/O and data path helper functionality.
*/
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/bitops.h>
#include <linux/rwsem.h>
#include <linux/fs.h>
#include <linux/nfs_fs.h>
#include "internal.h"
/* Call with exclusively locked inode->i_rwsem */
static
void
nfs_block_o_direct
(
struct
nfs_inode
*
nfsi
,
struct
inode
*
inode
)
{
if
(
test_bit
(
NFS_INO_ODIRECT
,
&
nfsi
->
flags
))
{
clear_bit
(
NFS_INO_ODIRECT
,
&
nfsi
->
flags
);
inode_dio_wait
(
inode
);
}
}
/**
* nfs_start_io_read - declare the file is being used for buffered reads
* @inode - file inode
*
* Declare that a buffered read operation is about to start, and ensure
* that we block all direct I/O.
* On exit, the function ensures that the NFS_INO_ODIRECT flag is unset,
* and holds a shared lock on inode->i_rwsem to ensure that the flag
* cannot be changed.
* In practice, this means that buffered read operations are allowed to
* execute in parallel, thanks to the shared lock, whereas direct I/O
* operations need to wait to grab an exclusive lock in order to set
* NFS_INO_ODIRECT.
* Note that buffered writes and truncates both take a write lock on
* inode->i_rwsem, meaning that those are serialised w.r.t. the reads.
*/
void
nfs_start_io_read
(
struct
inode
*
inode
)
{
struct
nfs_inode
*
nfsi
=
NFS_I
(
inode
);
/* Be an optimist! */
down_read
(
&
inode
->
i_rwsem
);
if
(
test_bit
(
NFS_INO_ODIRECT
,
&
nfsi
->
flags
)
==
0
)
return
;
up_read
(
&
inode
->
i_rwsem
);
/* Slow path.... */
down_write
(
&
inode
->
i_rwsem
);
nfs_block_o_direct
(
nfsi
,
inode
);
downgrade_write
(
&
inode
->
i_rwsem
);
}
/**
* nfs_end_io_read - declare that the buffered read operation is done
* @inode - file inode
*
* Declare that a buffered read operation is done, and release the shared
* lock on inode->i_rwsem.
*/
void
nfs_end_io_read
(
struct
inode
*
inode
)
{
up_read
(
&
inode
->
i_rwsem
);
}
/**
* nfs_start_io_write - declare the file is being used for buffered writes
* @inode - file inode
*
* Declare that a buffered read operation is about to start, and ensure
* that we block all direct I/O.
*/
void
nfs_start_io_write
(
struct
inode
*
inode
)
{
down_write
(
&
inode
->
i_rwsem
);
nfs_block_o_direct
(
NFS_I
(
inode
),
inode
);
}
/**
* nfs_end_io_write - declare that the buffered write operation is done
* @inode - file inode
*
* Declare that a buffered write operation is done, and release the
* lock on inode->i_rwsem.
*/
void
nfs_end_io_write
(
struct
inode
*
inode
)
{
up_write
(
&
inode
->
i_rwsem
);
}
/* Call with exclusively locked inode->i_rwsem */
static
void
nfs_block_buffered
(
struct
nfs_inode
*
nfsi
,
struct
inode
*
inode
)
{
if
(
!
test_bit
(
NFS_INO_ODIRECT
,
&
nfsi
->
flags
))
{
set_bit
(
NFS_INO_ODIRECT
,
&
nfsi
->
flags
);
nfs_wb_all
(
inode
);
}
}
/**
* nfs_end_io_direct - declare the file is being used for direct i/o
* @inode - file inode
*
* Declare that a direct I/O operation is about to start, and ensure
* that we block all buffered I/O.
* On exit, the function ensures that the NFS_INO_ODIRECT flag is set,
* and holds a shared lock on inode->i_rwsem to ensure that the flag
* cannot be changed.
* In practice, this means that direct I/O operations are allowed to
* execute in parallel, thanks to the shared lock, whereas buffered I/O
* operations need to wait to grab an exclusive lock in order to clear
* NFS_INO_ODIRECT.
* Note that buffered writes and truncates both take a write lock on
* inode->i_rwsem, meaning that those are serialised w.r.t. O_DIRECT.
*/
void
nfs_start_io_direct
(
struct
inode
*
inode
)
{
struct
nfs_inode
*
nfsi
=
NFS_I
(
inode
);
/* Be an optimist! */
down_read
(
&
inode
->
i_rwsem
);
if
(
test_bit
(
NFS_INO_ODIRECT
,
&
nfsi
->
flags
)
!=
0
)
return
;
up_read
(
&
inode
->
i_rwsem
);
/* Slow path.... */
down_write
(
&
inode
->
i_rwsem
);
nfs_block_buffered
(
nfsi
,
inode
);
downgrade_write
(
&
inode
->
i_rwsem
);
}
/**
* nfs_end_io_direct - declare that the direct i/o operation is done
* @inode - file inode
*
* Declare that a direct I/O operation is done, and release the shared
* lock on inode->i_rwsem.
*/
void
nfs_end_io_direct
(
struct
inode
*
inode
)
{
up_read
(
&
inode
->
i_rwsem
);
}
fs/nfs/nfs42proc.c
View file @
36274526
...
...
@@ -113,15 +113,17 @@ int nfs42_proc_deallocate(struct file *filep, loff_t offset, loff_t len)
if
(
!
nfs_server_capable
(
inode
,
NFS_CAP_DEALLOCATE
))
return
-
EOPNOTSUPP
;
nfs_wb_all
(
inode
);
inode_lock
(
inode
);
err
=
nfs_sync_inode
(
inode
);
if
(
err
)
goto
out_unlock
;
err
=
nfs42_proc_fallocate
(
&
msg
,
filep
,
offset
,
len
);
if
(
err
==
0
)
truncate_pagecache_range
(
inode
,
offset
,
(
offset
+
len
)
-
1
);
if
(
err
==
-
EOPNOTSUPP
)
NFS_SERVER
(
inode
)
->
caps
&=
~
NFS_CAP_DEALLOCATE
;
out_unlock:
inode_unlock
(
inode
);
return
err
;
}
...
...
@@ -154,11 +156,20 @@ static ssize_t _nfs42_proc_copy(struct file *src, loff_t pos_src,
if
(
status
)
return
status
;
status
=
nfs_filemap_write_and_wait_range
(
file_inode
(
src
)
->
i_mapping
,
pos_src
,
pos_src
+
(
loff_t
)
count
-
1
);
if
(
status
)
return
status
;
status
=
nfs4_set_rw_stateid
(
&
args
.
dst_stateid
,
dst_lock
->
open_context
,
dst_lock
,
FMODE_WRITE
);
if
(
status
)
return
status
;
status
=
nfs_sync_inode
(
dst_inode
);
if
(
status
)
return
status
;
status
=
nfs4_call_sync
(
server
->
client
,
server
,
&
msg
,
&
args
.
seq_args
,
&
res
.
seq_res
,
0
);
if
(
status
==
-
ENOTSUPP
)
...
...
@@ -258,7 +269,11 @@ static loff_t _nfs42_proc_llseek(struct file *filep,
if
(
status
)
return
status
;
nfs_wb_all
(
inode
);
status
=
nfs_filemap_write_and_wait_range
(
inode
->
i_mapping
,
offset
,
LLONG_MAX
);
if
(
status
)
return
status
;
status
=
nfs4_call_sync
(
server
->
client
,
server
,
&
msg
,
&
args
.
seq_args
,
&
res
.
seq_res
,
0
);
if
(
status
==
-
ENOTSUPP
)
...
...
fs/nfs/nfs4file.c
View file @
36274526
...
...
@@ -66,7 +66,7 @@ nfs4_file_open(struct inode *inode, struct file *filp)
if
(
openflags
&
O_TRUNC
)
{
attr
.
ia_valid
|=
ATTR_SIZE
;
attr
.
ia_size
=
0
;
nfs_sync_inode
(
inode
);
filemap_write_and_wait
(
inode
->
i_mapping
);
}
inode
=
NFS_PROTO
(
dir
)
->
open_context
(
dir
,
ctx
,
openflags
,
&
attr
,
NULL
);
...
...
@@ -133,21 +133,9 @@ static ssize_t nfs4_copy_file_range(struct file *file_in, loff_t pos_in,
struct
file
*
file_out
,
loff_t
pos_out
,
size_t
count
,
unsigned
int
flags
)
{
struct
inode
*
in_inode
=
file_inode
(
file_in
);
struct
inode
*
out_inode
=
file_inode
(
file_out
);
int
ret
;
if
(
in_inode
==
out_inode
)
if
(
file_inode
(
file_in
)
==
file_inode
(
file_out
))
return
-
EINVAL
;
/* flush any pending writes */
ret
=
nfs_sync_inode
(
in_inode
);
if
(
ret
)
return
ret
;
ret
=
nfs_sync_inode
(
out_inode
);
if
(
ret
)
return
ret
;
return
nfs42_proc_copy
(
file_in
,
pos_in
,
file_out
,
pos_out
,
count
);
}
...
...
fs/nfs/nfs4xdr.c
View file @
36274526
...
...
@@ -1985,9 +1985,14 @@ encode_layoutcommit(struct xdr_stream *xdr,
p
=
xdr_encode_hyper
(
p
,
args
->
lastbytewritten
+
1
);
/* length */
*
p
=
cpu_to_be32
(
0
);
/* reclaim */
encode_nfs4_stateid
(
xdr
,
&
args
->
stateid
);
p
=
reserve_space
(
xdr
,
20
);
*
p
++
=
cpu_to_be32
(
1
);
/* newoffset = TRUE */
p
=
xdr_encode_hyper
(
p
,
args
->
lastbytewritten
);
if
(
args
->
lastbytewritten
!=
U64_MAX
)
{
p
=
reserve_space
(
xdr
,
20
);
*
p
++
=
cpu_to_be32
(
1
);
/* newoffset = TRUE */
p
=
xdr_encode_hyper
(
p
,
args
->
lastbytewritten
);
}
else
{
p
=
reserve_space
(
xdr
,
12
);
*
p
++
=
cpu_to_be32
(
0
);
/* newoffset = FALSE */
}
*
p
++
=
cpu_to_be32
(
0
);
/* Never send time_modify_changed */
*
p
++
=
cpu_to_be32
(
NFS_SERVER
(
args
->
inode
)
->
pnfs_curr_ld
->
id
);
/* type */
...
...
fs/nfs/nfstrace.h
View file @
36274526
...
...
@@ -37,7 +37,6 @@
{ 1 << NFS_INO_ADVISE_RDPLUS, "ADVISE_RDPLUS" }, \
{ 1 << NFS_INO_STALE, "STALE" }, \
{ 1 << NFS_INO_INVALIDATING, "INVALIDATING" }, \
{ 1 << NFS_INO_FLUSHING, "FLUSHING" }, \
{ 1 << NFS_INO_FSCACHE, "FSCACHE" }, \
{ 1 << NFS_INO_LAYOUTCOMMIT, "NEED_LAYOUTCOMMIT" }, \
{ 1 << NFS_INO_LAYOUTCOMMITTING, "LAYOUTCOMMIT" })
...
...
fs/nfs/pnfs.c
View file @
36274526
...
...
@@ -2393,7 +2393,10 @@ pnfs_layoutcommit_inode(struct inode *inode, bool sync)
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
;
if
(
end_pos
!=
0
)
data
->
args
.
lastbytewritten
=
end_pos
-
1
;
else
data
->
args
.
lastbytewritten
=
U64_MAX
;
data
->
res
.
server
=
NFS_SERVER
(
inode
);
if
(
ld
->
prepare_layoutcommit
)
{
...
...
fs/nfs/pnfs.h
View file @
36274526
...
...
@@ -628,6 +628,13 @@ pnfs_sync_inode(struct inode *inode, bool datasync)
return
0
;
}
static
inline
bool
pnfs_layoutcommit_outstanding
(
struct
inode
*
inode
)
{
return
false
;
}
static
inline
bool
pnfs_roc
(
struct
inode
*
ino
)
{
...
...
@@ -716,13 +723,6 @@ pnfs_use_threshold(struct nfs4_threshold **dst, struct nfs4_threshold *src,
return
false
;
}
static
inline
bool
pnfs_layoutcommit_outstanding
(
struct
inode
*
inode
)
{
return
false
;
}
static
inline
struct
nfs4_threshold
*
pnfs_mdsthreshold_alloc
(
void
)
{
return
NULL
;
...
...
fs/nfs/pnfs_nfs.c
View file @
36274526
...
...
@@ -940,6 +940,13 @@ EXPORT_SYMBOL_GPL(pnfs_layout_mark_request_commit);
int
pnfs_nfs_generic_sync
(
struct
inode
*
inode
,
bool
datasync
)
{
int
ret
;
if
(
!
pnfs_layoutcommit_outstanding
(
inode
))
return
0
;
ret
=
nfs_commit_inode
(
inode
,
FLUSH_SYNC
);
if
(
ret
<
0
)
return
ret
;
if
(
datasync
)
return
0
;
return
pnfs_layoutcommit_inode
(
inode
,
true
);
...
...
fs/nfs/write.c
View file @
36274526
...
...
@@ -625,7 +625,7 @@ static int nfs_writepage_locked(struct page *page,
int
err
;
nfs_inc_stats
(
inode
,
NFSIOS_VFSWRITEPAGE
);
nfs_pageio_init_write
(
&
pgio
,
inode
,
wb_priority
(
wbc
)
,
nfs_pageio_init_write
(
&
pgio
,
inode
,
0
,
false
,
&
nfs_async_write_completion_ops
);
err
=
nfs_do_writepage
(
page
,
wbc
,
&
pgio
,
launder
);
nfs_pageio_complete
(
&
pgio
);
...
...
@@ -657,16 +657,9 @@ static int nfs_writepages_callback(struct page *page, struct writeback_control *
int
nfs_writepages
(
struct
address_space
*
mapping
,
struct
writeback_control
*
wbc
)
{
struct
inode
*
inode
=
mapping
->
host
;
unsigned
long
*
bitlock
=
&
NFS_I
(
inode
)
->
flags
;
struct
nfs_pageio_descriptor
pgio
;
int
err
;
/* Stop dirtying of new pages while we sync */
err
=
wait_on_bit_lock_action
(
bitlock
,
NFS_INO_FLUSHING
,
nfs_wait_bit_killable
,
TASK_KILLABLE
);
if
(
err
)
goto
out_err
;
nfs_inc_stats
(
inode
,
NFSIOS_VFSWRITEPAGES
);
nfs_pageio_init_write
(
&
pgio
,
inode
,
wb_priority
(
wbc
),
false
,
...
...
@@ -674,10 +667,6 @@ int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc)
err
=
write_cache_pages
(
mapping
,
wbc
,
nfs_writepages_callback
,
&
pgio
);
nfs_pageio_complete
(
&
pgio
);
clear_bit_unlock
(
NFS_INO_FLUSHING
,
bitlock
);
smp_mb__after_atomic
();
wake_up_bit
(
bitlock
,
NFS_INO_FLUSHING
);
if
(
err
<
0
)
goto
out_err
;
err
=
pgio
.
pg_error
;
...
...
@@ -1805,7 +1794,7 @@ static void nfs_commit_release_pages(struct nfs_commit_data *data)
/* Okay, COMMIT succeeded, apparently. Check the verifier
* returned by the server against all stored verfs. */
if
(
!
memcmp
(
&
req
->
wb_verf
,
&
data
->
verf
.
verifier
,
sizeof
(
req
->
wb_verf
)
))
{
if
(
!
nfs_write_verifier_cmp
(
&
req
->
wb_verf
,
&
data
->
verf
.
verifier
))
{
/* We have a match */
nfs_inode_remove_request
(
req
);
dprintk
(
" OK
\n
"
);
...
...
@@ -1928,6 +1917,24 @@ int nfs_write_inode(struct inode *inode, struct writeback_control *wbc)
}
EXPORT_SYMBOL_GPL
(
nfs_write_inode
);
/*
* Wrapper for filemap_write_and_wait_range()
*
* Needed for pNFS in order to ensure data becomes visible to the
* client.
*/
int
nfs_filemap_write_and_wait_range
(
struct
address_space
*
mapping
,
loff_t
lstart
,
loff_t
lend
)
{
int
ret
;
ret
=
filemap_write_and_wait_range
(
mapping
,
lstart
,
lend
);
if
(
ret
==
0
)
ret
=
pnfs_sync_inode
(
mapping
->
host
,
true
);
return
ret
;
}
EXPORT_SYMBOL_GPL
(
nfs_filemap_write_and_wait_range
);
/*
* flush the inode to disk.
*/
...
...
include/linux/nfs_fs.h
View file @
36274526
...
...
@@ -205,12 +205,12 @@ struct nfs_inode {
#define NFS_INO_STALE (1)
/* possible stale inode */
#define NFS_INO_ACL_LRU_SET (2)
/* Inode is on the LRU list */
#define NFS_INO_INVALIDATING (3)
/* inode is being invalidated */
#define NFS_INO_FLUSHING (4)
/* inode is flushing out data */
#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_LAYOUTCOMMIT (9)
/* layoutcommit required */
#define NFS_INO_LAYOUTCOMMITTING (10)
/* layoutcommit inflight */
#define NFS_INO_LAYOUTSTATS (11)
/* layoutstats inflight */
#define NFS_INO_ODIRECT (12)
/* I/O setting is O_DIRECT */
static
inline
struct
nfs_inode
*
NFS_I
(
const
struct
inode
*
inode
)
{
...
...
@@ -351,7 +351,6 @@ extern int nfs_revalidate_inode_rcu(struct nfs_server *server, struct inode *ino
extern
int
__nfs_revalidate_inode
(
struct
nfs_server
*
,
struct
inode
*
);
extern
int
nfs_revalidate_mapping
(
struct
inode
*
inode
,
struct
address_space
*
mapping
);
extern
int
nfs_revalidate_mapping_rcu
(
struct
inode
*
inode
);
extern
int
nfs_revalidate_mapping_protected
(
struct
inode
*
inode
,
struct
address_space
*
mapping
);
extern
int
nfs_setattr
(
struct
dentry
*
,
struct
iattr
*
);
extern
void
nfs_setattr_update_inode
(
struct
inode
*
inode
,
struct
iattr
*
attr
,
struct
nfs_fattr
*
);
extern
void
nfs_setsecurity
(
struct
inode
*
inode
,
struct
nfs_fattr
*
fattr
,
...
...
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