mirror of
https://github.com/torvalds/linux.git
synced 2024-11-22 04:38:03 +00:00
NFS client updates for Linux 6.7
Highlights include: Bugfixes: - SUNRPC: A fix to re-probe the target RPC port after an ECONNRESET error - SUNRPC: Handle allocation errors from rpcb_call_async() - SUNRPC: Fix a use-after-free condition in rpc_pipefs - SUNRPC: fix up various checks for timeouts - NFSv4.1: Handle NFS4ERR_DELAY errors during session trunking - NFSv4.1: 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 -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEESQctxSBg8JpV8KqEZwvnipYKAPIFAmVL62IACgkQZwvnipYK API4Ww/+I75hmEdI4i/6v8WnrLWLWzmCgybez2AfrKYtuYmEcDZTf2K4pNVEJxFG PJ4TYRpaSgwxCXqoup5INOdL5gS8g3JbAlTqrDQ8nYGeBXETN9tN5n2Xj8liHk2l OrnYzgTjC2pwpWDZq/W1LCQMatCbs9XhpmyBvqZH5r7tAOVGkrk1ICZ/r+/nGiN8 LAbm/I0M1Jp0iJisN/i/0CsEgLQMCfeQVrtEMCZGsoVS79Mr/W1hF3KiGognI/xz FvEXnZKauw9npu7U7ckhHZcHd8oQxby0Q0Xny/IpgiO2Z1YqfKCvJSK1sjBt/lFu 7fe2HGMFfcTMx/bn/qdUJR351607rBi4h3t1OfK4KIxV1gSLUyS/RR7ayFx5A0gM pFJcC0ZnKoiVr2vSNMMguennbyjScqNOC5ECb+bpMAyDV7suF9e/khK12CdYwqFm cpeUUD35GZT+RjP3htI92Pj0bqBOHx+o7qEi+MEel3t90us8PPBrWywHk7Tw40vJ eUxH0XQtZVswH6TvekNdoMXx8TXSAbx4I6Hw3fmNGWLRp494p3GVSmWQmctcvCi7 Y6E1P3YT8G1OeI9+fIQr5Wp2F9sOdFPrb3BrAojj9ndJ3ZqQAcx+gY5z2RVnvvur PTsLInFxS8+WvvqPtQCZZ5UxnrcPFCk1js0rg6EqdjZmq6+OqJU= =TNRl -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
6bc986ab83
@ -3596,6 +3596,13 @@
|
||||
[NFS] set the TCP port on which the NFSv4 callback
|
||||
channel should listen.
|
||||
|
||||
nfs.delay_retrans=
|
||||
[NFS] specifies the number of times the NFSv4 client
|
||||
retries the request before returning an EAGAIN error,
|
||||
after a reply of NFS4ERR_DELAY from the server.
|
||||
Only applies if the softerr mount option is enabled,
|
||||
and the specified value is >= 0.
|
||||
|
||||
nfs.enable_ino64=
|
||||
[NFS] enable 64-bit inode numbers.
|
||||
If zero, the NFS client will fake up a 32-bit inode
|
||||
|
@ -125,7 +125,7 @@ config PNFS_BLOCK
|
||||
|
||||
config PNFS_FLEXFILE_LAYOUT
|
||||
tristate
|
||||
depends on NFS_V4_1 && NFS_V3
|
||||
depends on NFS_V4_1
|
||||
default NFS_V4
|
||||
|
||||
config NFS_V4_1_IMPLEMENTATION_ID_DOMAIN
|
||||
|
@ -448,6 +448,7 @@ int nfs_inode_set_delegation(struct inode *inode, const struct cred *cred,
|
||||
delegation->cred = get_cred(cred);
|
||||
delegation->inode = inode;
|
||||
delegation->flags = 1<<NFS_DELEGATION_REFERENCED;
|
||||
delegation->test_gen = 0;
|
||||
spin_lock_init(&delegation->lock);
|
||||
|
||||
spin_lock(&clp->cl_lock);
|
||||
@ -1294,6 +1295,8 @@ static int nfs_server_reap_expired_delegations(struct nfs_server *server,
|
||||
struct inode *inode;
|
||||
const struct cred *cred;
|
||||
nfs4_stateid stateid;
|
||||
unsigned long gen = ++server->delegation_gen;
|
||||
|
||||
restart:
|
||||
rcu_read_lock();
|
||||
restart_locked:
|
||||
@ -1303,7 +1306,8 @@ static int nfs_server_reap_expired_delegations(struct nfs_server *server,
|
||||
test_bit(NFS_DELEGATION_RETURNING,
|
||||
&delegation->flags) ||
|
||||
test_bit(NFS_DELEGATION_TEST_EXPIRED,
|
||||
&delegation->flags) == 0)
|
||||
&delegation->flags) == 0 ||
|
||||
delegation->test_gen == gen)
|
||||
continue;
|
||||
inode = nfs_delegation_grab_inode(delegation);
|
||||
if (inode == NULL)
|
||||
@ -1312,6 +1316,7 @@ static int nfs_server_reap_expired_delegations(struct nfs_server *server,
|
||||
cred = get_cred_rcu(delegation->cred);
|
||||
nfs4_stateid_copy(&stateid, &delegation->stateid);
|
||||
spin_unlock(&delegation->lock);
|
||||
delegation->test_gen = gen;
|
||||
clear_bit(NFS_DELEGATION_TEST_EXPIRED, &delegation->flags);
|
||||
rcu_read_unlock();
|
||||
nfs_delegation_test_free_expired(inode, &stateid, cred);
|
||||
|
@ -21,6 +21,7 @@ struct nfs_delegation {
|
||||
fmode_t type;
|
||||
unsigned long pagemod_limit;
|
||||
__u64 change_attr;
|
||||
unsigned long test_gen;
|
||||
unsigned long flags;
|
||||
refcount_t refcount;
|
||||
spinlock_t lock;
|
||||
|
29
fs/nfs/dir.c
29
fs/nfs/dir.c
@ -2532,7 +2532,7 @@ EXPORT_SYMBOL_GPL(nfs_unlink);
|
||||
int nfs_symlink(struct mnt_idmap *idmap, struct inode *dir,
|
||||
struct dentry *dentry, const char *symname)
|
||||
{
|
||||
struct page *page;
|
||||
struct folio *folio;
|
||||
char *kaddr;
|
||||
struct iattr attr;
|
||||
unsigned int pathlen = strlen(symname);
|
||||
@ -2547,24 +2547,24 @@ int nfs_symlink(struct mnt_idmap *idmap, struct inode *dir,
|
||||
attr.ia_mode = S_IFLNK | S_IRWXUGO;
|
||||
attr.ia_valid = ATTR_MODE;
|
||||
|
||||
page = alloc_page(GFP_USER);
|
||||
if (!page)
|
||||
folio = folio_alloc(GFP_USER, 0);
|
||||
if (!folio)
|
||||
return -ENOMEM;
|
||||
|
||||
kaddr = page_address(page);
|
||||
kaddr = folio_address(folio);
|
||||
memcpy(kaddr, symname, pathlen);
|
||||
if (pathlen < PAGE_SIZE)
|
||||
memset(kaddr + pathlen, 0, PAGE_SIZE - pathlen);
|
||||
|
||||
trace_nfs_symlink_enter(dir, dentry);
|
||||
error = NFS_PROTO(dir)->symlink(dir, dentry, page, pathlen, &attr);
|
||||
error = NFS_PROTO(dir)->symlink(dir, dentry, folio, pathlen, &attr);
|
||||
trace_nfs_symlink_exit(dir, dentry, error);
|
||||
if (error != 0) {
|
||||
dfprintk(VFS, "NFS: symlink(%s/%lu, %pd, %s) error %d\n",
|
||||
dir->i_sb->s_id, dir->i_ino,
|
||||
dentry, symname, error);
|
||||
d_drop(dentry);
|
||||
__free_page(page);
|
||||
folio_put(folio);
|
||||
return error;
|
||||
}
|
||||
|
||||
@ -2574,18 +2574,13 @@ int nfs_symlink(struct mnt_idmap *idmap, struct inode *dir,
|
||||
* No big deal if we can't add this page to the page cache here.
|
||||
* READLINK will get the missing page from the server if needed.
|
||||
*/
|
||||
if (!add_to_page_cache_lru(page, d_inode(dentry)->i_mapping, 0,
|
||||
GFP_KERNEL)) {
|
||||
SetPageUptodate(page);
|
||||
unlock_page(page);
|
||||
/*
|
||||
* add_to_page_cache_lru() grabs an extra page refcount.
|
||||
* Drop it here to avoid leaking this page later.
|
||||
*/
|
||||
put_page(page);
|
||||
} else
|
||||
__free_page(page);
|
||||
if (filemap_add_folio(d_inode(dentry)->i_mapping, folio, 0,
|
||||
GFP_KERNEL) == 0) {
|
||||
folio_mark_uptodate(folio);
|
||||
folio_unlock(folio);
|
||||
}
|
||||
|
||||
folio_put(folio);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nfs_symlink);
|
||||
|
@ -543,9 +543,10 @@ nfs3_proc_link(struct inode *inode, struct inode *dir, const struct qstr *name)
|
||||
}
|
||||
|
||||
static int
|
||||
nfs3_proc_symlink(struct inode *dir, struct dentry *dentry, struct page *page,
|
||||
nfs3_proc_symlink(struct inode *dir, struct dentry *dentry, struct folio *folio,
|
||||
unsigned int len, struct iattr *sattr)
|
||||
{
|
||||
struct page *page = &folio->page;
|
||||
struct nfs3_createdata *data;
|
||||
struct dentry *d_alias;
|
||||
int status = -ENOMEM;
|
||||
|
@ -209,6 +209,7 @@ struct nfs4_exception {
|
||||
struct inode *inode;
|
||||
nfs4_stateid *stateid;
|
||||
long timeout;
|
||||
unsigned short retrans;
|
||||
unsigned char task_is_privileged : 1;
|
||||
unsigned char delay : 1,
|
||||
recovering : 1,
|
||||
@ -546,6 +547,7 @@ extern unsigned short max_session_slots;
|
||||
extern unsigned short max_session_cb_slots;
|
||||
extern unsigned short send_implementation_id;
|
||||
extern bool recover_lost_locks;
|
||||
extern short nfs_delay_retrans;
|
||||
|
||||
#define NFS4_CLIENT_ID_UNIQ_LEN (64)
|
||||
extern char nfs4_client_id_uniquifier[NFS4_CLIENT_ID_UNIQ_LEN];
|
||||
|
@ -585,6 +585,21 @@ static int nfs4_do_handle_exception(struct nfs_server *server,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Track the number of NFS4ERR_DELAY related retransmissions and return
|
||||
* EAGAIN if the 'softerr' mount option is set, and we've exceeded the limit
|
||||
* set by 'nfs_delay_retrans'.
|
||||
*/
|
||||
static int nfs4_exception_should_retrans(const struct nfs_server *server,
|
||||
struct nfs4_exception *exception)
|
||||
{
|
||||
if (server->flags & NFS_MOUNT_SOFTERR && nfs_delay_retrans >= 0) {
|
||||
if (exception->retrans++ >= (unsigned short)nfs_delay_retrans)
|
||||
return -EAGAIN;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This is the error handling routine for processes that are allowed
|
||||
* to sleep.
|
||||
*/
|
||||
@ -595,6 +610,11 @@ int nfs4_handle_exception(struct nfs_server *server, int errorcode, struct nfs4_
|
||||
|
||||
ret = nfs4_do_handle_exception(server, errorcode, exception);
|
||||
if (exception->delay) {
|
||||
int ret2 = nfs4_exception_should_retrans(server, exception);
|
||||
if (ret2 < 0) {
|
||||
exception->retry = 0;
|
||||
return ret2;
|
||||
}
|
||||
ret = nfs4_delay(&exception->timeout,
|
||||
exception->interruptible);
|
||||
goto out_retry;
|
||||
@ -623,6 +643,11 @@ nfs4_async_handle_exception(struct rpc_task *task, struct nfs_server *server,
|
||||
|
||||
ret = nfs4_do_handle_exception(server, errorcode, exception);
|
||||
if (exception->delay) {
|
||||
int ret2 = nfs4_exception_should_retrans(server, exception);
|
||||
if (ret2 < 0) {
|
||||
exception->retry = 0;
|
||||
return ret2;
|
||||
}
|
||||
rpc_delay(task, nfs4_update_delay(&exception->timeout));
|
||||
goto out_retry;
|
||||
}
|
||||
@ -5011,9 +5036,10 @@ static void nfs4_free_createdata(struct nfs4_createdata *data)
|
||||
}
|
||||
|
||||
static int _nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
|
||||
struct page *page, unsigned int len, struct iattr *sattr,
|
||||
struct folio *folio, unsigned int len, struct iattr *sattr,
|
||||
struct nfs4_label *label)
|
||||
{
|
||||
struct page *page = &folio->page;
|
||||
struct nfs4_createdata *data;
|
||||
int status = -ENAMETOOLONG;
|
||||
|
||||
@ -5038,7 +5064,7 @@ static int _nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
|
||||
}
|
||||
|
||||
static int nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
|
||||
struct page *page, unsigned int len, struct iattr *sattr)
|
||||
struct folio *folio, unsigned int len, struct iattr *sattr)
|
||||
{
|
||||
struct nfs4_exception exception = {
|
||||
.interruptible = true,
|
||||
@ -5049,7 +5075,7 @@ static int nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
|
||||
label = nfs4_label_init_security(dir, dentry, sattr, &l);
|
||||
|
||||
do {
|
||||
err = _nfs4_proc_symlink(dir, dentry, page, len, sattr, label);
|
||||
err = _nfs4_proc_symlink(dir, dentry, folio, len, sattr, label);
|
||||
trace_nfs4_symlink(dir, &dentry->d_name, err);
|
||||
err = nfs4_handle_exception(NFS_SERVER(dir), err,
|
||||
&exception);
|
||||
@ -5622,7 +5648,7 @@ static void nfs4_proc_write_setup(struct nfs_pgio_header *hdr,
|
||||
|
||||
msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_WRITE];
|
||||
nfs4_init_sequence(&hdr->args.seq_args, &hdr->res.seq_res, 0, 0);
|
||||
nfs4_state_protect_write(server->nfs_client, clnt, msg, hdr);
|
||||
nfs4_state_protect_write(hdr->ds_clp ? hdr->ds_clp : server->nfs_client, clnt, msg, hdr);
|
||||
}
|
||||
|
||||
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
|
||||
data->res.server = server;
|
||||
msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COMMIT];
|
||||
nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 1, 0);
|
||||
nfs4_state_protect(server->nfs_client, NFS_SP4_MACH_CRED_COMMIT, clnt, msg);
|
||||
nfs4_state_protect(data->ds_clp ? data->ds_clp : server->nfs_client,
|
||||
NFS_SP4_MACH_CRED_COMMIT, clnt, msg);
|
||||
}
|
||||
|
||||
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,
|
||||
|
||||
sp4_how = (adata->clp->cl_sp4_flags == 0 ? SP4_NONE : SP4_MACH_CRED);
|
||||
|
||||
try_again:
|
||||
/* Test connection for session trunking. Async exchange_id call */
|
||||
task = nfs4_run_exchange_id(adata->clp, adata->cred, sp4_how, xprt);
|
||||
if (IS_ERR(task))
|
||||
@ -8946,11 +8974,15 @@ void nfs4_test_session_trunk(struct rpc_clnt *clnt, struct rpc_xprt *xprt,
|
||||
|
||||
if (status == 0)
|
||||
rpc_clnt_xprt_switch_add_xprt(clnt, xprt);
|
||||
else if (rpc_clnt_xprt_switch_has_addr(clnt,
|
||||
else if (status != -NFS4ERR_DELAY && rpc_clnt_xprt_switch_has_addr(clnt,
|
||||
(struct sockaddr *)&xprt->addr))
|
||||
rpc_clnt_xprt_switch_remove_xprt(clnt, xprt);
|
||||
|
||||
rpc_put_task(task);
|
||||
if (status == -NFS4ERR_DELAY) {
|
||||
ssleep(1);
|
||||
goto try_again;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nfs4_test_session_trunk);
|
||||
|
||||
@ -9621,6 +9653,9 @@ nfs4_layoutget_handle_exception(struct rpc_task *task,
|
||||
|
||||
nfs4_sequence_free_slot(&lgp->res.seq_res);
|
||||
|
||||
exception->state = NULL;
|
||||
exception->stateid = NULL;
|
||||
|
||||
switch (nfs4err) {
|
||||
case 0:
|
||||
goto out;
|
||||
@ -9716,7 +9751,8 @@ static const struct rpc_call_ops nfs4_layoutget_call_ops = {
|
||||
};
|
||||
|
||||
struct pnfs_layout_segment *
|
||||
nfs4_proc_layoutget(struct nfs4_layoutget *lgp, long *timeout)
|
||||
nfs4_proc_layoutget(struct nfs4_layoutget *lgp,
|
||||
struct nfs4_exception *exception)
|
||||
{
|
||||
struct inode *inode = lgp->args.inode;
|
||||
struct nfs_server *server = NFS_SERVER(inode);
|
||||
@ -9736,13 +9772,10 @@ nfs4_proc_layoutget(struct nfs4_layoutget *lgp, long *timeout)
|
||||
RPC_TASK_MOVEABLE,
|
||||
};
|
||||
struct pnfs_layout_segment *lseg = NULL;
|
||||
struct nfs4_exception exception = {
|
||||
.inode = inode,
|
||||
.timeout = *timeout,
|
||||
};
|
||||
int status = 0;
|
||||
|
||||
nfs4_init_sequence(&lgp->args.seq_args, &lgp->res.seq_res, 0, 0);
|
||||
exception->retry = 0;
|
||||
|
||||
task = rpc_run_task(&task_setup_data);
|
||||
if (IS_ERR(task))
|
||||
@ -9753,11 +9786,12 @@ nfs4_proc_layoutget(struct nfs4_layoutget *lgp, long *timeout)
|
||||
goto out;
|
||||
|
||||
if (task->tk_status < 0) {
|
||||
status = nfs4_layoutget_handle_exception(task, lgp, &exception);
|
||||
*timeout = exception.timeout;
|
||||
exception->retry = 1;
|
||||
status = nfs4_layoutget_handle_exception(task, lgp, exception);
|
||||
} else if (lgp->res.layoutp->len == 0) {
|
||||
exception->retry = 1;
|
||||
status = -EAGAIN;
|
||||
*timeout = nfs4_update_delay(&exception.timeout);
|
||||
nfs4_update_delay(&exception->timeout);
|
||||
} else
|
||||
lseg = pnfs_layout_process(lgp);
|
||||
out:
|
||||
|
@ -1980,7 +1980,9 @@ pnfs_update_layout(struct inode *ino,
|
||||
struct pnfs_layout_segment *lseg = NULL;
|
||||
struct nfs4_layoutget *lgp;
|
||||
nfs4_stateid stateid;
|
||||
long timeout = 0;
|
||||
struct nfs4_exception exception = {
|
||||
.inode = ino,
|
||||
};
|
||||
unsigned long giveup = jiffies + (clp->cl_lease_time << 1);
|
||||
bool first;
|
||||
|
||||
@ -2144,7 +2146,7 @@ pnfs_update_layout(struct inode *ino,
|
||||
lgp->lo = lo;
|
||||
pnfs_get_layout_hdr(lo);
|
||||
|
||||
lseg = nfs4_proc_layoutget(lgp, &timeout);
|
||||
lseg = nfs4_proc_layoutget(lgp, &exception);
|
||||
trace_pnfs_update_layout(ino, pos, count, iomode, lo, lseg,
|
||||
PNFS_UPDATE_LAYOUT_SEND_LAYOUTGET);
|
||||
nfs_layoutget_end(lo);
|
||||
@ -2171,6 +2173,8 @@ pnfs_update_layout(struct inode *ino,
|
||||
goto out_put_layout_hdr;
|
||||
}
|
||||
if (lseg) {
|
||||
if (!exception.retry)
|
||||
goto out_put_layout_hdr;
|
||||
if (first)
|
||||
pnfs_clear_first_layoutget(lo);
|
||||
trace_pnfs_update_layout(ino, pos, count,
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include <linux/nfs_page.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
struct nfs4_exception;
|
||||
struct nfs4_opendata;
|
||||
|
||||
enum {
|
||||
@ -245,7 +246,9 @@ extern size_t max_response_pages(struct nfs_server *server);
|
||||
extern int nfs4_proc_getdeviceinfo(struct nfs_server *server,
|
||||
struct pnfs_device *dev,
|
||||
const struct cred *cred);
|
||||
extern struct pnfs_layout_segment* nfs4_proc_layoutget(struct nfs4_layoutget *lgp, long *timeout);
|
||||
extern struct pnfs_layout_segment *
|
||||
nfs4_proc_layoutget(struct nfs4_layoutget *lgp,
|
||||
struct nfs4_exception *exception);
|
||||
extern int nfs4_proc_layoutreturn(struct nfs4_layoutreturn *lrp, bool sync);
|
||||
|
||||
/* pnfs.c */
|
||||
|
@ -396,9 +396,10 @@ nfs_proc_link(struct inode *inode, struct inode *dir, const struct qstr *name)
|
||||
}
|
||||
|
||||
static int
|
||||
nfs_proc_symlink(struct inode *dir, struct dentry *dentry, struct page *page,
|
||||
nfs_proc_symlink(struct inode *dir, struct dentry *dentry, struct folio *folio,
|
||||
unsigned int len, struct iattr *sattr)
|
||||
{
|
||||
struct page *page = &folio->page;
|
||||
struct nfs_fh *fh;
|
||||
struct nfs_fattr *fattr;
|
||||
struct nfs_symlinkargs arg = {
|
||||
|
@ -1371,6 +1371,7 @@ unsigned short max_session_cb_slots = NFS4_DEF_CB_SLOT_TABLE_SIZE;
|
||||
unsigned short send_implementation_id = 1;
|
||||
char nfs4_client_id_uniquifier[NFS4_CLIENT_ID_UNIQ_LEN] = "";
|
||||
bool recover_lost_locks = false;
|
||||
short nfs_delay_retrans = -1;
|
||||
|
||||
EXPORT_SYMBOL_GPL(nfs_callback_nr_threads);
|
||||
EXPORT_SYMBOL_GPL(nfs_callback_set_tcpport);
|
||||
@ -1381,6 +1382,7 @@ EXPORT_SYMBOL_GPL(max_session_cb_slots);
|
||||
EXPORT_SYMBOL_GPL(send_implementation_id);
|
||||
EXPORT_SYMBOL_GPL(nfs4_client_id_uniquifier);
|
||||
EXPORT_SYMBOL_GPL(recover_lost_locks);
|
||||
EXPORT_SYMBOL_GPL(nfs_delay_retrans);
|
||||
|
||||
#define NFS_CALLBACK_MAXPORTNR (65535U)
|
||||
|
||||
@ -1429,5 +1431,9 @@ MODULE_PARM_DESC(recover_lost_locks,
|
||||
"If the server reports that a lock might be lost, "
|
||||
"try to recover it risking data corruption.");
|
||||
|
||||
|
||||
module_param_named(delay_retrans, nfs_delay_retrans, short, 0644);
|
||||
MODULE_PARM_DESC(delay_retrans,
|
||||
"Unless negative, specifies the number of times the NFSv4 "
|
||||
"client retries a request before returning an EAGAIN error, "
|
||||
"after a reply of NFS4ERR_DELAY from the server.");
|
||||
#endif /* CONFIG_NFS_V4 */
|
||||
|
@ -739,6 +739,8 @@ int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc)
|
||||
&pgio);
|
||||
pgio.pg_error = 0;
|
||||
nfs_pageio_complete(&pgio);
|
||||
if (err == -EAGAIN && mntflags & NFS_MOUNT_SOFTERR)
|
||||
break;
|
||||
} while (err < 0 && !nfs_error_is_fatal(err));
|
||||
nfs_io_completion_put(ioc);
|
||||
|
||||
|
@ -239,6 +239,7 @@ struct nfs_server {
|
||||
struct list_head delegations;
|
||||
struct list_head ss_copies;
|
||||
|
||||
unsigned long delegation_gen;
|
||||
unsigned long mig_gen;
|
||||
unsigned long mig_status;
|
||||
#define NFS_MIG_IN_TRANSITION (1)
|
||||
|
@ -1772,7 +1772,7 @@ struct nfs_rpc_ops {
|
||||
void (*rename_rpc_prepare)(struct rpc_task *task, struct nfs_renamedata *);
|
||||
int (*rename_done) (struct rpc_task *task, struct inode *old_dir, struct inode *new_dir);
|
||||
int (*link) (struct inode *, struct inode *, const struct qstr *);
|
||||
int (*symlink) (struct inode *, struct dentry *, struct page *,
|
||||
int (*symlink) (struct inode *, struct dentry *, struct folio *,
|
||||
unsigned int, struct iattr *);
|
||||
int (*mkdir) (struct inode *, struct dentry *, struct iattr *);
|
||||
int (*rmdir) (struct inode *, const struct qstr *);
|
||||
|
@ -92,6 +92,7 @@ struct rpc_clnt {
|
||||
};
|
||||
const struct cred *cl_cred;
|
||||
unsigned int cl_max_connect; /* max number of transports not to the same IP */
|
||||
struct super_block *pipefs_sb;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -111,7 +111,8 @@ static void rpc_clnt_remove_pipedir(struct rpc_clnt *clnt)
|
||||
|
||||
pipefs_sb = rpc_get_sb_net(net);
|
||||
if (pipefs_sb) {
|
||||
__rpc_clnt_remove_pipedir(clnt);
|
||||
if (pipefs_sb == clnt->pipefs_sb)
|
||||
__rpc_clnt_remove_pipedir(clnt);
|
||||
rpc_put_sb_net(net);
|
||||
}
|
||||
}
|
||||
@ -151,6 +152,8 @@ rpc_setup_pipedir(struct super_block *pipefs_sb, struct rpc_clnt *clnt)
|
||||
{
|
||||
struct dentry *dentry;
|
||||
|
||||
clnt->pipefs_sb = pipefs_sb;
|
||||
|
||||
if (clnt->cl_program->pipe_dir_name != NULL) {
|
||||
dentry = rpc_setup_pipedir_sb(pipefs_sb, clnt);
|
||||
if (IS_ERR(dentry))
|
||||
@ -2171,6 +2174,7 @@ call_connect_status(struct rpc_task *task)
|
||||
task->tk_status = 0;
|
||||
switch (status) {
|
||||
case -ECONNREFUSED:
|
||||
case -ECONNRESET:
|
||||
/* A positive refusal suggests a rebind is needed. */
|
||||
if (RPC_IS_SOFTCONN(task))
|
||||
break;
|
||||
@ -2179,7 +2183,6 @@ call_connect_status(struct rpc_task *task)
|
||||
goto out_retry;
|
||||
}
|
||||
fallthrough;
|
||||
case -ECONNRESET:
|
||||
case -ECONNABORTED:
|
||||
case -ENETDOWN:
|
||||
case -ENETUNREACH:
|
||||
@ -2220,7 +2223,7 @@ call_connect_status(struct rpc_task *task)
|
||||
}
|
||||
xprt_switch_put(xps);
|
||||
if (!task->tk_xprt)
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
goto out_retry;
|
||||
case -ENOBUFS:
|
||||
@ -2235,6 +2238,7 @@ call_connect_status(struct rpc_task *task)
|
||||
out_retry:
|
||||
/* Check for timeouts before looping back to call_bind */
|
||||
task->tk_action = call_bind;
|
||||
out:
|
||||
rpc_check_timeout(task);
|
||||
}
|
||||
|
||||
|
@ -769,6 +769,10 @@ void rpcb_getport_async(struct rpc_task *task)
|
||||
|
||||
child = rpcb_call_async(rpcb_clnt, map, proc);
|
||||
rpc_release_client(rpcb_clnt);
|
||||
if (IS_ERR(child)) {
|
||||
/* rpcb_map_release() has freed the arguments */
|
||||
return;
|
||||
}
|
||||
|
||||
xprt->stat.bind_count++;
|
||||
rpc_put_task(child);
|
||||
|
@ -283,7 +283,7 @@ int xprt_reserve_xprt(struct rpc_xprt *xprt, struct rpc_task *task)
|
||||
xprt_clear_locked(xprt);
|
||||
out_sleep:
|
||||
task->tk_status = -EAGAIN;
|
||||
if (RPC_IS_SOFT(task))
|
||||
if (RPC_IS_SOFT(task) || RPC_IS_SOFTCONN(task))
|
||||
rpc_sleep_on_timeout(&xprt->sending, task, NULL,
|
||||
xprt_request_timeout(req));
|
||||
else
|
||||
@ -349,7 +349,7 @@ int xprt_reserve_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task)
|
||||
xprt_clear_locked(xprt);
|
||||
out_sleep:
|
||||
task->tk_status = -EAGAIN;
|
||||
if (RPC_IS_SOFT(task))
|
||||
if (RPC_IS_SOFT(task) || RPC_IS_SOFTCONN(task))
|
||||
rpc_sleep_on_timeout(&xprt->sending, task, NULL,
|
||||
xprt_request_timeout(req));
|
||||
else
|
||||
|
@ -1181,6 +1181,7 @@ static void xs_sock_reset_state_flags(struct rpc_xprt *xprt)
|
||||
{
|
||||
struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
|
||||
|
||||
transport->xprt_err = 0;
|
||||
clear_bit(XPRT_SOCK_DATA_READY, &transport->sock_state);
|
||||
clear_bit(XPRT_SOCK_WAKE_ERROR, &transport->sock_state);
|
||||
clear_bit(XPRT_SOCK_WAKE_WRITE, &transport->sock_state);
|
||||
@ -2772,18 +2773,13 @@ static void xs_wake_error(struct sock_xprt *transport)
|
||||
{
|
||||
int sockerr;
|
||||
|
||||
if (!test_bit(XPRT_SOCK_WAKE_ERROR, &transport->sock_state))
|
||||
return;
|
||||
mutex_lock(&transport->recv_mutex);
|
||||
if (transport->sock == NULL)
|
||||
goto out;
|
||||
if (!test_and_clear_bit(XPRT_SOCK_WAKE_ERROR, &transport->sock_state))
|
||||
goto out;
|
||||
return;
|
||||
sockerr = xchg(&transport->xprt_err, 0);
|
||||
if (sockerr < 0)
|
||||
if (sockerr < 0) {
|
||||
xprt_wake_pending_tasks(&transport->xprt, sockerr);
|
||||
out:
|
||||
mutex_unlock(&transport->recv_mutex);
|
||||
xs_tcp_force_close(&transport->xprt);
|
||||
}
|
||||
}
|
||||
|
||||
static void xs_wake_pending(struct sock_xprt *transport)
|
||||
|
Loading…
Reference in New Issue
Block a user