Skip to content

Commit 75f26df

Browse files
committed
Merge tag 'nfs-for-4.5-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
Pull NFS client updates from Trond Myklebust: "Highlights include: Stable fixes: - Fix a regression in the SunRPC socket polling code - Fix the attribute cache revalidation code - Fix race in __update_open_stateid() - Fix an lo->plh_block_lgets imbalance in layoutreturn - Fix an Oopsable typo in ff_mirror_match_fh() Features: - pNFS layout recall performance improvements. - pNFS/flexfiles: Support server-supplied layoutstats sampling period Bugfixes + cleanups: - NFSv4: Don't perform cached access checks before we've OPENed the file - Fix starvation issues with background flushes - Reclaim writes should be flushed as unstable writes if there are already entries in the commit lists - Various bugfixes from Chuck to fix NFS/RDMA send queue ordering problems - Ensure that we propagate fatal layoutget errors back to the application - Fixes for sundry flexfiles layoutstats bugs - Fix files/flexfiles to not cache invalidated layouts in the DS commit buckets" * tag 'nfs-for-4.5-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs: (68 commits) NFS: Fix a compile warning about unused variable in nfs_generic_pg_pgios() NFSv4: Fix a compile warning about no prototype for nfs4_ioctl() NFS: Use wait_on_atomic_t() for unlock after readahead SUNRPC: Fixup socket wait for memory NFSv4.1/pNFS: Cleanup constify struct pnfs_layout_range arguments NFSv4.1/pnfs: Cleanup copying of pnfs_layout_range structures NFSv4.1/pNFS: Cleanup pnfs_mark_matching_lsegs_invalid() NFSv4.1/pNFS: Fix a race in initiate_file_draining() NFSv4.1/pNFS: pnfs_error_mark_layout_for_return() must always return layout NFSv4.1/pNFS: pnfs_mark_matching_lsegs_return() should set the iomode NFSv4.1/pNFS: Use nfs4_stateid_copy for copying stateids NFSv4.1/pNFS: Don't pass stateids by value to pnfs_send_layoutreturn() NFS: Relax requirements in nfs_flush_incompatible NFSv4.1/pNFS: Don't queue up a new commit if the layout segment is invalid NFS: Allow multiple commit requests in flight per file NFS/pNFS: Fix up pNFS write reschedule layering violations and bugs SUNRPC: Fix a missing break in rpc_anyaddr() pNFS/flexfiles: Fix an Oopsable typo in ff_mirror_match_fh() NFS: Fix attribute cache revalidation NFS: Ensure we revalidate attributes before using execute_ok() ...
2 parents 63f729c + 44aab3e commit 75f26df

36 files changed

+1480
-519
lines changed

fs/nfs/callback_proc.c

Lines changed: 45 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,11 @@ __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy,
8383

8484
res = htonl(NFS4ERR_BADHANDLE);
8585
inode = nfs_delegation_find_inode(cps->clp, &args->fh);
86-
if (inode == NULL)
86+
if (inode == NULL) {
87+
trace_nfs4_cb_recall(cps->clp, &args->fh, NULL,
88+
&args->stateid, -ntohl(res));
8789
goto out;
90+
}
8891
/* Set up a helper thread to actually return the delegation */
8992
switch (nfs_async_inode_return_delegation(inode, &args->stateid)) {
9093
case 0:
@@ -96,7 +99,8 @@ __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy,
9699
default:
97100
res = htonl(NFS4ERR_RESOURCE);
98101
}
99-
trace_nfs4_recall_delegation(inode, -ntohl(res));
102+
trace_nfs4_cb_recall(cps->clp, &args->fh, inode,
103+
&args->stateid, -ntohl(res));
100104
iput(inode);
101105
out:
102106
dprintk("%s: exit with status = %d\n", __func__, ntohl(res));
@@ -160,6 +164,22 @@ static struct pnfs_layout_hdr * get_layout_by_fh(struct nfs_client *clp,
160164
return lo;
161165
}
162166

167+
/*
168+
* Enforce RFC5661 section 12.5.5.2.1. (Layout Recall and Return Sequencing)
169+
*/
170+
static bool pnfs_check_stateid_sequence(struct pnfs_layout_hdr *lo,
171+
const nfs4_stateid *new)
172+
{
173+
u32 oldseq, newseq;
174+
175+
oldseq = be32_to_cpu(lo->plh_stateid.seqid);
176+
newseq = be32_to_cpu(new->seqid);
177+
178+
if (newseq > oldseq + 1)
179+
return false;
180+
return true;
181+
}
182+
163183
static u32 initiate_file_draining(struct nfs_client *clp,
164184
struct cb_layoutrecallargs *args)
165185
{
@@ -169,34 +189,52 @@ static u32 initiate_file_draining(struct nfs_client *clp,
169189
LIST_HEAD(free_me_list);
170190

171191
lo = get_layout_by_fh(clp, &args->cbl_fh, &args->cbl_stateid);
172-
if (!lo)
192+
if (!lo) {
193+
trace_nfs4_cb_layoutrecall_file(clp, &args->cbl_fh, NULL,
194+
&args->cbl_stateid, -rv);
173195
goto out;
196+
}
174197

175198
ino = lo->plh_inode;
176199

177200
spin_lock(&ino->i_lock);
201+
if (!pnfs_check_stateid_sequence(lo, &args->cbl_stateid)) {
202+
rv = NFS4ERR_DELAY;
203+
goto unlock;
204+
}
178205
pnfs_set_layout_stateid(lo, &args->cbl_stateid, true);
179206
spin_unlock(&ino->i_lock);
180207

181208
pnfs_layoutcommit_inode(ino, false);
182209

183210
spin_lock(&ino->i_lock);
184-
if (test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags) ||
185-
pnfs_mark_matching_lsegs_invalid(lo, &free_me_list,
186-
&args->cbl_range)) {
211+
/*
212+
* Enforce RFC5661 Section 12.5.5.2.1.5 (Bulk Recall and Return)
213+
*/
214+
if (test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags)) {
187215
rv = NFS4ERR_DELAY;
188216
goto unlock;
189217
}
190218

219+
if (pnfs_mark_matching_lsegs_return(lo, &free_me_list,
220+
&args->cbl_range)) {
221+
rv = NFS4_OK;
222+
goto unlock;
223+
}
224+
191225
if (NFS_SERVER(ino)->pnfs_curr_ld->return_range) {
192226
NFS_SERVER(ino)->pnfs_curr_ld->return_range(lo,
193227
&args->cbl_range);
194228
}
229+
pnfs_mark_layout_returned_if_empty(lo);
195230
unlock:
196231
spin_unlock(&ino->i_lock);
197232
pnfs_free_lseg_list(&free_me_list);
233+
/* Free all lsegs that are attached to commit buckets */
234+
nfs_commit_inode(ino, 0);
198235
pnfs_put_layout_hdr(lo);
199-
trace_nfs4_cb_layoutrecall_inode(clp, &args->cbl_fh, ino, -rv);
236+
trace_nfs4_cb_layoutrecall_file(clp, &args->cbl_fh, ino,
237+
&args->cbl_stateid, -rv);
200238
iput(ino);
201239
out:
202240
return rv;

fs/nfs/dir.c

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2431,6 +2431,20 @@ int nfs_may_open(struct inode *inode, struct rpc_cred *cred, int openflags)
24312431
}
24322432
EXPORT_SYMBOL_GPL(nfs_may_open);
24332433

2434+
static int nfs_execute_ok(struct inode *inode, int mask)
2435+
{
2436+
struct nfs_server *server = NFS_SERVER(inode);
2437+
int ret;
2438+
2439+
if (mask & MAY_NOT_BLOCK)
2440+
ret = nfs_revalidate_inode_rcu(server, inode);
2441+
else
2442+
ret = nfs_revalidate_inode(server, inode);
2443+
if (ret == 0 && !execute_ok(inode))
2444+
ret = -EACCES;
2445+
return ret;
2446+
}
2447+
24342448
int nfs_permission(struct inode *inode, int mask)
24352449
{
24362450
struct rpc_cred *cred;
@@ -2448,6 +2462,9 @@ int nfs_permission(struct inode *inode, int mask)
24482462
case S_IFLNK:
24492463
goto out;
24502464
case S_IFREG:
2465+
if ((mask & MAY_OPEN) &&
2466+
nfs_server_capable(inode, NFS_CAP_ATOMIC_OPEN))
2467+
return 0;
24512468
break;
24522469
case S_IFDIR:
24532470
/*
@@ -2480,8 +2497,8 @@ int nfs_permission(struct inode *inode, int mask)
24802497
res = PTR_ERR(cred);
24812498
}
24822499
out:
2483-
if (!res && (mask & MAY_EXEC) && !execute_ok(inode))
2484-
res = -EACCES;
2500+
if (!res && (mask & MAY_EXEC))
2501+
res = nfs_execute_ok(inode, mask);
24852502

24862503
dfprintk(VFS, "NFS: permission(%s/%lu), mask=0x%x, res=%d\n",
24872504
inode->i_sb->s_id, inode->i_ino, mask, res);

fs/nfs/direct.c

Lines changed: 38 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -117,12 +117,6 @@ static inline int put_dreq(struct nfs_direct_req *dreq)
117117
return atomic_dec_and_test(&dreq->io_count);
118118
}
119119

120-
void nfs_direct_set_resched_writes(struct nfs_direct_req *dreq)
121-
{
122-
dreq->flags = NFS_ODIRECT_RESCHED_WRITES;
123-
}
124-
EXPORT_SYMBOL_GPL(nfs_direct_set_resched_writes);
125-
126120
static void
127121
nfs_direct_good_bytes(struct nfs_direct_req *dreq, struct nfs_pgio_header *hdr)
128122
{
@@ -670,20 +664,28 @@ static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq)
670664

671665
req = nfs_list_entry(reqs.next);
672666
nfs_direct_setup_mirroring(dreq, &desc, req);
667+
if (desc.pg_error < 0) {
668+
list_splice_init(&reqs, &failed);
669+
goto out_failed;
670+
}
673671

674672
list_for_each_entry_safe(req, tmp, &reqs, wb_list) {
675673
if (!nfs_pageio_add_request(&desc, req)) {
676674
nfs_list_remove_request(req);
677675
nfs_list_add_request(req, &failed);
678676
spin_lock(cinfo.lock);
679677
dreq->flags = 0;
680-
dreq->error = -EIO;
678+
if (desc.pg_error < 0)
679+
dreq->error = desc.pg_error;
680+
else
681+
dreq->error = -EIO;
681682
spin_unlock(cinfo.lock);
682683
}
683684
nfs_release_request(req);
684685
}
685686
nfs_pageio_complete(&desc);
686687

688+
out_failed:
687689
while (!list_empty(&failed)) {
688690
req = nfs_list_entry(failed.next);
689691
nfs_list_remove_request(req);
@@ -727,14 +729,20 @@ static void nfs_direct_commit_complete(struct nfs_commit_data *data)
727729
nfs_direct_write_complete(dreq, data->inode);
728730
}
729731

730-
static void nfs_direct_error_cleanup(struct nfs_inode *nfsi)
732+
static void nfs_direct_resched_write(struct nfs_commit_info *cinfo,
733+
struct nfs_page *req)
731734
{
732-
/* There is no lock to clear */
735+
struct nfs_direct_req *dreq = cinfo->dreq;
736+
737+
spin_lock(&dreq->lock);
738+
dreq->flags = NFS_ODIRECT_RESCHED_WRITES;
739+
spin_unlock(&dreq->lock);
740+
nfs_mark_request_commit(req, NULL, cinfo, 0);
733741
}
734742

735743
static const struct nfs_commit_completion_ops nfs_direct_commit_completion_ops = {
736744
.completion = nfs_direct_commit_complete,
737-
.error_cleanup = nfs_direct_error_cleanup,
745+
.resched_write = nfs_direct_resched_write,
738746
};
739747

740748
static void nfs_direct_commit_schedule(struct nfs_direct_req *dreq)
@@ -839,10 +847,25 @@ static void nfs_write_sync_pgio_error(struct list_head *head)
839847
}
840848
}
841849

850+
static void nfs_direct_write_reschedule_io(struct nfs_pgio_header *hdr)
851+
{
852+
struct nfs_direct_req *dreq = hdr->dreq;
853+
854+
spin_lock(&dreq->lock);
855+
if (dreq->error == 0) {
856+
dreq->flags = NFS_ODIRECT_RESCHED_WRITES;
857+
/* fake unstable write to let common nfs resend pages */
858+
hdr->verf.committed = NFS_UNSTABLE;
859+
hdr->good_bytes = hdr->args.count;
860+
}
861+
spin_unlock(&dreq->lock);
862+
}
863+
842864
static const struct nfs_pgio_completion_ops nfs_direct_write_completion_ops = {
843865
.error_cleanup = nfs_write_sync_pgio_error,
844866
.init_hdr = nfs_direct_pgio_init,
845867
.completion = nfs_direct_write_completion,
868+
.reschedule_io = nfs_direct_write_reschedule_io,
846869
};
847870

848871

@@ -900,6 +923,11 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq,
900923
}
901924

902925
nfs_direct_setup_mirroring(dreq, &desc, req);
926+
if (desc.pg_error < 0) {
927+
nfs_free_request(req);
928+
result = desc.pg_error;
929+
break;
930+
}
903931

904932
nfs_lock_request(req);
905933
req->wb_index = pos >> PAGE_SHIFT;

fs/nfs/file.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -514,7 +514,7 @@ static void nfs_check_dirty_writeback(struct page *page,
514514
* so it will not block due to pages that will shortly be freeable.
515515
*/
516516
nfsi = NFS_I(mapping->host);
517-
if (test_bit(NFS_INO_COMMIT, &nfsi->flags)) {
517+
if (atomic_read(&nfsi->commit_info.rpcs_out)) {
518518
*writeback = true;
519519
return;
520520
}
@@ -545,7 +545,7 @@ static int nfs_launder_page(struct page *page)
545545
inode->i_ino, (long long)page_offset(page));
546546

547547
nfs_fscache_wait_on_page_write(nfsi, page);
548-
return nfs_wb_page(inode, page);
548+
return nfs_wb_launder_page(inode, page);
549549
}
550550

551551
static int nfs_swap_activate(struct swap_info_struct *sis, struct file *file,
@@ -756,7 +756,7 @@ do_unlk(struct file *filp, int cmd, struct file_lock *fl, int is_local)
756756

757757
l_ctx = nfs_get_lock_context(nfs_file_open_context(filp));
758758
if (!IS_ERR(l_ctx)) {
759-
status = nfs_iocounter_wait(&l_ctx->io_count);
759+
status = nfs_iocounter_wait(l_ctx);
760760
nfs_put_lock_context(l_ctx);
761761
if (status < 0)
762762
return status;

fs/nfs/filelayout/filelayout.c

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,7 @@ static int filelayout_async_handle_error(struct rpc_task *task,
202202
task->tk_status);
203203
nfs4_mark_deviceid_unavailable(devid);
204204
pnfs_error_mark_layout_for_return(inode, lseg);
205+
pnfs_set_lo_fail(lseg);
205206
rpc_wake_up(&tbl->slot_tbl_waitq);
206207
/* fall through */
207208
default:
@@ -883,13 +884,19 @@ static void
883884
filelayout_pg_init_read(struct nfs_pageio_descriptor *pgio,
884885
struct nfs_page *req)
885886
{
886-
if (!pgio->pg_lseg)
887+
if (!pgio->pg_lseg) {
887888
pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode,
888889
req->wb_context,
889890
0,
890891
NFS4_MAX_UINT64,
891892
IOMODE_READ,
892893
GFP_KERNEL);
894+
if (IS_ERR(pgio->pg_lseg)) {
895+
pgio->pg_error = PTR_ERR(pgio->pg_lseg);
896+
pgio->pg_lseg = NULL;
897+
return;
898+
}
899+
}
893900
/* If no lseg, fall back to read through mds */
894901
if (pgio->pg_lseg == NULL)
895902
nfs_pageio_reset_read_mds(pgio);
@@ -902,13 +909,20 @@ filelayout_pg_init_write(struct nfs_pageio_descriptor *pgio,
902909
struct nfs_commit_info cinfo;
903910
int status;
904911

905-
if (!pgio->pg_lseg)
912+
if (!pgio->pg_lseg) {
906913
pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode,
907914
req->wb_context,
908915
0,
909916
NFS4_MAX_UINT64,
910917
IOMODE_RW,
911918
GFP_NOFS);
919+
if (IS_ERR(pgio->pg_lseg)) {
920+
pgio->pg_error = PTR_ERR(pgio->pg_lseg);
921+
pgio->pg_lseg = NULL;
922+
return;
923+
}
924+
}
925+
912926
/* If no lseg, fall back to write through mds */
913927
if (pgio->pg_lseg == NULL)
914928
goto out_mds;

0 commit comments

Comments
 (0)