Skip to content

Commit 6bc986a

Browse files
committed
Merge tag 'nfs-for-6.7-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
Pull NFS client updates from Trond Myklebust: "Bugfixes: - SUNRPC: - re-probe the target RPC port after an ECONNRESET error - handle allocation errors from rpcb_call_async() - fix a use-after-free condition in rpc_pipefs - fix up various checks for timeouts - NFSv4.1: - Handle NFS4ERR_DELAY errors during session trunking - fix SP4_MACH_CRED protection for pnfs IO - NFSv4: - Ensure that we test all delegations when the server notifies us that it may have revoked some of them Features: - Allow knfsd processes to break out of NFS4ERR_DELAY loops when re-exporting NFSv4.x by setting appropriate values for the 'delay_retrans' module parameter - nfs: Convert nfs_symlink() to use a folio" * tag 'nfs-for-6.7-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs: nfs: Convert nfs_symlink() to use a folio SUNRPC: Fix RPC client cleaned up the freed pipefs dentries NFSv4.1: fix SP4_MACH_CRED protection for pnfs IO SUNRPC: Add an IS_ERR() check back to where it was NFSv4.1: fix handling NFS4ERR_DELAY when testing for session trunking nfs41: drop dependency between flexfiles layout driver and NFSv3 modules NFSv4: fairly test all delegations on a SEQ4_ revocation SUNRPC: SOFTCONN tasks should time out when on the sending list SUNRPC: Force close the socket when a hard error is reported SUNRPC: Don't skip timeout checks in call_connect_status() SUNRPC: ECONNRESET might require a rebind NFSv4/pnfs: Allow layoutget to return EAGAIN for softerr mounts NFSv4: Add a parameter to limit the number of retries after NFS4ERR_DELAY
2 parents 67c0afb + f003a71 commit 6bc986a

File tree

20 files changed

+121
-54
lines changed

20 files changed

+121
-54
lines changed

Documentation/admin-guide/kernel-parameters.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3596,6 +3596,13 @@
35963596
[NFS] set the TCP port on which the NFSv4 callback
35973597
channel should listen.
35983598

3599+
nfs.delay_retrans=
3600+
[NFS] specifies the number of times the NFSv4 client
3601+
retries the request before returning an EAGAIN error,
3602+
after a reply of NFS4ERR_DELAY from the server.
3603+
Only applies if the softerr mount option is enabled,
3604+
and the specified value is >= 0.
3605+
35993606
nfs.enable_ino64=
36003607
[NFS] enable 64-bit inode numbers.
36013608
If zero, the NFS client will fake up a 32-bit inode

fs/nfs/Kconfig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ config PNFS_BLOCK
125125

126126
config PNFS_FLEXFILE_LAYOUT
127127
tristate
128-
depends on NFS_V4_1 && NFS_V3
128+
depends on NFS_V4_1
129129
default NFS_V4
130130

131131
config NFS_V4_1_IMPLEMENTATION_ID_DOMAIN

fs/nfs/delegation.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,7 @@ int nfs_inode_set_delegation(struct inode *inode, const struct cred *cred,
448448
delegation->cred = get_cred(cred);
449449
delegation->inode = inode;
450450
delegation->flags = 1<<NFS_DELEGATION_REFERENCED;
451+
delegation->test_gen = 0;
451452
spin_lock_init(&delegation->lock);
452453

453454
spin_lock(&clp->cl_lock);
@@ -1294,6 +1295,8 @@ static int nfs_server_reap_expired_delegations(struct nfs_server *server,
12941295
struct inode *inode;
12951296
const struct cred *cred;
12961297
nfs4_stateid stateid;
1298+
unsigned long gen = ++server->delegation_gen;
1299+
12971300
restart:
12981301
rcu_read_lock();
12991302
restart_locked:
@@ -1303,7 +1306,8 @@ static int nfs_server_reap_expired_delegations(struct nfs_server *server,
13031306
test_bit(NFS_DELEGATION_RETURNING,
13041307
&delegation->flags) ||
13051308
test_bit(NFS_DELEGATION_TEST_EXPIRED,
1306-
&delegation->flags) == 0)
1309+
&delegation->flags) == 0 ||
1310+
delegation->test_gen == gen)
13071311
continue;
13081312
inode = nfs_delegation_grab_inode(delegation);
13091313
if (inode == NULL)
@@ -1312,6 +1316,7 @@ static int nfs_server_reap_expired_delegations(struct nfs_server *server,
13121316
cred = get_cred_rcu(delegation->cred);
13131317
nfs4_stateid_copy(&stateid, &delegation->stateid);
13141318
spin_unlock(&delegation->lock);
1319+
delegation->test_gen = gen;
13151320
clear_bit(NFS_DELEGATION_TEST_EXPIRED, &delegation->flags);
13161321
rcu_read_unlock();
13171322
nfs_delegation_test_free_expired(inode, &stateid, cred);

fs/nfs/delegation.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ struct nfs_delegation {
2121
fmode_t type;
2222
unsigned long pagemod_limit;
2323
__u64 change_attr;
24+
unsigned long test_gen;
2425
unsigned long flags;
2526
refcount_t refcount;
2627
spinlock_t lock;

fs/nfs/dir.c

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2532,7 +2532,7 @@ EXPORT_SYMBOL_GPL(nfs_unlink);
25322532
int nfs_symlink(struct mnt_idmap *idmap, struct inode *dir,
25332533
struct dentry *dentry, const char *symname)
25342534
{
2535-
struct page *page;
2535+
struct folio *folio;
25362536
char *kaddr;
25372537
struct iattr attr;
25382538
unsigned int pathlen = strlen(symname);
@@ -2547,24 +2547,24 @@ int nfs_symlink(struct mnt_idmap *idmap, struct inode *dir,
25472547
attr.ia_mode = S_IFLNK | S_IRWXUGO;
25482548
attr.ia_valid = ATTR_MODE;
25492549

2550-
page = alloc_page(GFP_USER);
2551-
if (!page)
2550+
folio = folio_alloc(GFP_USER, 0);
2551+
if (!folio)
25522552
return -ENOMEM;
25532553

2554-
kaddr = page_address(page);
2554+
kaddr = folio_address(folio);
25552555
memcpy(kaddr, symname, pathlen);
25562556
if (pathlen < PAGE_SIZE)
25572557
memset(kaddr + pathlen, 0, PAGE_SIZE - pathlen);
25582558

25592559
trace_nfs_symlink_enter(dir, dentry);
2560-
error = NFS_PROTO(dir)->symlink(dir, dentry, page, pathlen, &attr);
2560+
error = NFS_PROTO(dir)->symlink(dir, dentry, folio, pathlen, &attr);
25612561
trace_nfs_symlink_exit(dir, dentry, error);
25622562
if (error != 0) {
25632563
dfprintk(VFS, "NFS: symlink(%s/%lu, %pd, %s) error %d\n",
25642564
dir->i_sb->s_id, dir->i_ino,
25652565
dentry, symname, error);
25662566
d_drop(dentry);
2567-
__free_page(page);
2567+
folio_put(folio);
25682568
return error;
25692569
}
25702570

@@ -2574,18 +2574,13 @@ int nfs_symlink(struct mnt_idmap *idmap, struct inode *dir,
25742574
* No big deal if we can't add this page to the page cache here.
25752575
* READLINK will get the missing page from the server if needed.
25762576
*/
2577-
if (!add_to_page_cache_lru(page, d_inode(dentry)->i_mapping, 0,
2578-
GFP_KERNEL)) {
2579-
SetPageUptodate(page);
2580-
unlock_page(page);
2581-
/*
2582-
* add_to_page_cache_lru() grabs an extra page refcount.
2583-
* Drop it here to avoid leaking this page later.
2584-
*/
2585-
put_page(page);
2586-
} else
2587-
__free_page(page);
2577+
if (filemap_add_folio(d_inode(dentry)->i_mapping, folio, 0,
2578+
GFP_KERNEL) == 0) {
2579+
folio_mark_uptodate(folio);
2580+
folio_unlock(folio);
2581+
}
25882582

2583+
folio_put(folio);
25892584
return 0;
25902585
}
25912586
EXPORT_SYMBOL_GPL(nfs_symlink);

fs/nfs/nfs3proc.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -543,9 +543,10 @@ nfs3_proc_link(struct inode *inode, struct inode *dir, const struct qstr *name)
543543
}
544544

545545
static int
546-
nfs3_proc_symlink(struct inode *dir, struct dentry *dentry, struct page *page,
546+
nfs3_proc_symlink(struct inode *dir, struct dentry *dentry, struct folio *folio,
547547
unsigned int len, struct iattr *sattr)
548548
{
549+
struct page *page = &folio->page;
549550
struct nfs3_createdata *data;
550551
struct dentry *d_alias;
551552
int status = -ENOMEM;

fs/nfs/nfs4_fs.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,7 @@ struct nfs4_exception {
209209
struct inode *inode;
210210
nfs4_stateid *stateid;
211211
long timeout;
212+
unsigned short retrans;
212213
unsigned char task_is_privileged : 1;
213214
unsigned char delay : 1,
214215
recovering : 1,
@@ -546,6 +547,7 @@ extern unsigned short max_session_slots;
546547
extern unsigned short max_session_cb_slots;
547548
extern unsigned short send_implementation_id;
548549
extern bool recover_lost_locks;
550+
extern short nfs_delay_retrans;
549551

550552
#define NFS4_CLIENT_ID_UNIQ_LEN (64)
551553
extern char nfs4_client_id_uniquifier[NFS4_CLIENT_ID_UNIQ_LEN];

fs/nfs/nfs4proc.c

Lines changed: 48 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -585,6 +585,21 @@ static int nfs4_do_handle_exception(struct nfs_server *server,
585585
return 0;
586586
}
587587

588+
/*
589+
* Track the number of NFS4ERR_DELAY related retransmissions and return
590+
* EAGAIN if the 'softerr' mount option is set, and we've exceeded the limit
591+
* set by 'nfs_delay_retrans'.
592+
*/
593+
static int nfs4_exception_should_retrans(const struct nfs_server *server,
594+
struct nfs4_exception *exception)
595+
{
596+
if (server->flags & NFS_MOUNT_SOFTERR && nfs_delay_retrans >= 0) {
597+
if (exception->retrans++ >= (unsigned short)nfs_delay_retrans)
598+
return -EAGAIN;
599+
}
600+
return 0;
601+
}
602+
588603
/* This is the error handling routine for processes that are allowed
589604
* to sleep.
590605
*/
@@ -595,6 +610,11 @@ int nfs4_handle_exception(struct nfs_server *server, int errorcode, struct nfs4_
595610

596611
ret = nfs4_do_handle_exception(server, errorcode, exception);
597612
if (exception->delay) {
613+
int ret2 = nfs4_exception_should_retrans(server, exception);
614+
if (ret2 < 0) {
615+
exception->retry = 0;
616+
return ret2;
617+
}
598618
ret = nfs4_delay(&exception->timeout,
599619
exception->interruptible);
600620
goto out_retry;
@@ -623,6 +643,11 @@ nfs4_async_handle_exception(struct rpc_task *task, struct nfs_server *server,
623643

624644
ret = nfs4_do_handle_exception(server, errorcode, exception);
625645
if (exception->delay) {
646+
int ret2 = nfs4_exception_should_retrans(server, exception);
647+
if (ret2 < 0) {
648+
exception->retry = 0;
649+
return ret2;
650+
}
626651
rpc_delay(task, nfs4_update_delay(&exception->timeout));
627652
goto out_retry;
628653
}
@@ -5011,9 +5036,10 @@ static void nfs4_free_createdata(struct nfs4_createdata *data)
50115036
}
50125037

50135038
static int _nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
5014-
struct page *page, unsigned int len, struct iattr *sattr,
5039+
struct folio *folio, unsigned int len, struct iattr *sattr,
50155040
struct nfs4_label *label)
50165041
{
5042+
struct page *page = &folio->page;
50175043
struct nfs4_createdata *data;
50185044
int status = -ENAMETOOLONG;
50195045

@@ -5038,7 +5064,7 @@ static int _nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
50385064
}
50395065

50405066
static int nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
5041-
struct page *page, unsigned int len, struct iattr *sattr)
5067+
struct folio *folio, unsigned int len, struct iattr *sattr)
50425068
{
50435069
struct nfs4_exception exception = {
50445070
.interruptible = true,
@@ -5049,7 +5075,7 @@ static int nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
50495075
label = nfs4_label_init_security(dir, dentry, sattr, &l);
50505076

50515077
do {
5052-
err = _nfs4_proc_symlink(dir, dentry, page, len, sattr, label);
5078+
err = _nfs4_proc_symlink(dir, dentry, folio, len, sattr, label);
50535079
trace_nfs4_symlink(dir, &dentry->d_name, err);
50545080
err = nfs4_handle_exception(NFS_SERVER(dir), err,
50555081
&exception);
@@ -5622,7 +5648,7 @@ static void nfs4_proc_write_setup(struct nfs_pgio_header *hdr,
56225648

56235649
msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_WRITE];
56245650
nfs4_init_sequence(&hdr->args.seq_args, &hdr->res.seq_res, 0, 0);
5625-
nfs4_state_protect_write(server->nfs_client, clnt, msg, hdr);
5651+
nfs4_state_protect_write(hdr->ds_clp ? hdr->ds_clp : server->nfs_client, clnt, msg, hdr);
56265652
}
56275653

56285654
static void nfs4_proc_commit_rpc_prepare(struct rpc_task *task, struct nfs_commit_data *data)
@@ -5663,7 +5689,8 @@ static void nfs4_proc_commit_setup(struct nfs_commit_data *data, struct rpc_mess
56635689
data->res.server = server;
56645690
msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COMMIT];
56655691
nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 1, 0);
5666-
nfs4_state_protect(server->nfs_client, NFS_SP4_MACH_CRED_COMMIT, clnt, msg);
5692+
nfs4_state_protect(data->ds_clp ? data->ds_clp : server->nfs_client,
5693+
NFS_SP4_MACH_CRED_COMMIT, clnt, msg);
56675694
}
56685695

56695696
static int _nfs4_proc_commit(struct file *dst, struct nfs_commitargs *args,
@@ -8934,6 +8961,7 @@ void nfs4_test_session_trunk(struct rpc_clnt *clnt, struct rpc_xprt *xprt,
89348961

89358962
sp4_how = (adata->clp->cl_sp4_flags == 0 ? SP4_NONE : SP4_MACH_CRED);
89368963

8964+
try_again:
89378965
/* Test connection for session trunking. Async exchange_id call */
89388966
task = nfs4_run_exchange_id(adata->clp, adata->cred, sp4_how, xprt);
89398967
if (IS_ERR(task))
@@ -8946,11 +8974,15 @@ void nfs4_test_session_trunk(struct rpc_clnt *clnt, struct rpc_xprt *xprt,
89468974

89478975
if (status == 0)
89488976
rpc_clnt_xprt_switch_add_xprt(clnt, xprt);
8949-
else if (rpc_clnt_xprt_switch_has_addr(clnt,
8977+
else if (status != -NFS4ERR_DELAY && rpc_clnt_xprt_switch_has_addr(clnt,
89508978
(struct sockaddr *)&xprt->addr))
89518979
rpc_clnt_xprt_switch_remove_xprt(clnt, xprt);
89528980

89538981
rpc_put_task(task);
8982+
if (status == -NFS4ERR_DELAY) {
8983+
ssleep(1);
8984+
goto try_again;
8985+
}
89548986
}
89558987
EXPORT_SYMBOL_GPL(nfs4_test_session_trunk);
89568988

@@ -9621,6 +9653,9 @@ nfs4_layoutget_handle_exception(struct rpc_task *task,
96219653

96229654
nfs4_sequence_free_slot(&lgp->res.seq_res);
96239655

9656+
exception->state = NULL;
9657+
exception->stateid = NULL;
9658+
96249659
switch (nfs4err) {
96259660
case 0:
96269661
goto out;
@@ -9716,7 +9751,8 @@ static const struct rpc_call_ops nfs4_layoutget_call_ops = {
97169751
};
97179752

97189753
struct pnfs_layout_segment *
9719-
nfs4_proc_layoutget(struct nfs4_layoutget *lgp, long *timeout)
9754+
nfs4_proc_layoutget(struct nfs4_layoutget *lgp,
9755+
struct nfs4_exception *exception)
97209756
{
97219757
struct inode *inode = lgp->args.inode;
97229758
struct nfs_server *server = NFS_SERVER(inode);
@@ -9736,13 +9772,10 @@ nfs4_proc_layoutget(struct nfs4_layoutget *lgp, long *timeout)
97369772
RPC_TASK_MOVEABLE,
97379773
};
97389774
struct pnfs_layout_segment *lseg = NULL;
9739-
struct nfs4_exception exception = {
9740-
.inode = inode,
9741-
.timeout = *timeout,
9742-
};
97439775
int status = 0;
97449776

97459777
nfs4_init_sequence(&lgp->args.seq_args, &lgp->res.seq_res, 0, 0);
9778+
exception->retry = 0;
97469779

97479780
task = rpc_run_task(&task_setup_data);
97489781
if (IS_ERR(task))
@@ -9753,11 +9786,12 @@ nfs4_proc_layoutget(struct nfs4_layoutget *lgp, long *timeout)
97539786
goto out;
97549787

97559788
if (task->tk_status < 0) {
9756-
status = nfs4_layoutget_handle_exception(task, lgp, &exception);
9757-
*timeout = exception.timeout;
9789+
exception->retry = 1;
9790+
status = nfs4_layoutget_handle_exception(task, lgp, exception);
97589791
} else if (lgp->res.layoutp->len == 0) {
9792+
exception->retry = 1;
97599793
status = -EAGAIN;
9760-
*timeout = nfs4_update_delay(&exception.timeout);
9794+
nfs4_update_delay(&exception->timeout);
97619795
} else
97629796
lseg = pnfs_layout_process(lgp);
97639797
out:

fs/nfs/pnfs.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1980,7 +1980,9 @@ pnfs_update_layout(struct inode *ino,
19801980
struct pnfs_layout_segment *lseg = NULL;
19811981
struct nfs4_layoutget *lgp;
19821982
nfs4_stateid stateid;
1983-
long timeout = 0;
1983+
struct nfs4_exception exception = {
1984+
.inode = ino,
1985+
};
19841986
unsigned long giveup = jiffies + (clp->cl_lease_time << 1);
19851987
bool first;
19861988

@@ -2144,7 +2146,7 @@ pnfs_update_layout(struct inode *ino,
21442146
lgp->lo = lo;
21452147
pnfs_get_layout_hdr(lo);
21462148

2147-
lseg = nfs4_proc_layoutget(lgp, &timeout);
2149+
lseg = nfs4_proc_layoutget(lgp, &exception);
21482150
trace_pnfs_update_layout(ino, pos, count, iomode, lo, lseg,
21492151
PNFS_UPDATE_LAYOUT_SEND_LAYOUTGET);
21502152
nfs_layoutget_end(lo);
@@ -2171,6 +2173,8 @@ pnfs_update_layout(struct inode *ino,
21712173
goto out_put_layout_hdr;
21722174
}
21732175
if (lseg) {
2176+
if (!exception.retry)
2177+
goto out_put_layout_hdr;
21742178
if (first)
21752179
pnfs_clear_first_layoutget(lo);
21762180
trace_pnfs_update_layout(ino, pos, count,

fs/nfs/pnfs.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#include <linux/nfs_page.h>
3636
#include <linux/workqueue.h>
3737

38+
struct nfs4_exception;
3839
struct nfs4_opendata;
3940

4041
enum {
@@ -245,7 +246,9 @@ extern size_t max_response_pages(struct nfs_server *server);
245246
extern int nfs4_proc_getdeviceinfo(struct nfs_server *server,
246247
struct pnfs_device *dev,
247248
const struct cred *cred);
248-
extern struct pnfs_layout_segment* nfs4_proc_layoutget(struct nfs4_layoutget *lgp, long *timeout);
249+
extern struct pnfs_layout_segment *
250+
nfs4_proc_layoutget(struct nfs4_layoutget *lgp,
251+
struct nfs4_exception *exception);
249252
extern int nfs4_proc_layoutreturn(struct nfs4_layoutreturn *lrp, bool sync);
250253

251254
/* pnfs.c */

fs/nfs/proc.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -396,9 +396,10 @@ nfs_proc_link(struct inode *inode, struct inode *dir, const struct qstr *name)
396396
}
397397

398398
static int
399-
nfs_proc_symlink(struct inode *dir, struct dentry *dentry, struct page *page,
399+
nfs_proc_symlink(struct inode *dir, struct dentry *dentry, struct folio *folio,
400400
unsigned int len, struct iattr *sattr)
401401
{
402+
struct page *page = &folio->page;
402403
struct nfs_fh *fh;
403404
struct nfs_fattr *fattr;
404405
struct nfs_symlinkargs arg = {

0 commit comments

Comments
 (0)