Skip to content

Commit

Permalink
Merge tag 'nfs-for-5.3-3' of git://git.linux-nfs.org/projects/trondmy…
Browse files Browse the repository at this point in the history
…/linux-nfs

Pull NFS client bugfixes from Trond Myklebust:
 "Highlights include:

  Stable fixes:

   - Fix a page lock leak in nfs_pageio_resend()

   - Ensure O_DIRECT reports an error if the bytes read/written is 0

   - Don't handle errors if the bind/connect succeeded

   - Revert "NFSv4/flexfiles: Abort I/O early if the layout segment was
     invalidat ed"

  Bugfixes:

   - Don't refresh attributes with mounted-on-file information

   - Fix return values for nfs4_file_open() and nfs_finish_open()

   - Fix pnfs layoutstats reporting of I/O errors

   - Don't use soft RPC calls for pNFS/flexfiles I/O, and don't abort
     for soft I/O errors when the user specifies a hard mount.

   - Various fixes to the error handling in sunrpc

   - Don't report writepage()/writepages() errors twice"

* tag 'nfs-for-5.3-3' of git://git.linux-nfs.org/projects/trondmy/linux-nfs:
  NFS: remove set but not used variable 'mapping'
  NFSv2: Fix write regression
  NFSv2: Fix eof handling
  NFS: Fix writepage(s) error handling to not report errors twice
  NFS: Fix spurious EIO read errors
  pNFS/flexfiles: Don't time out requests on hard mounts
  SUNRPC: Handle connection breakages correctly in call_status()
  Revert "NFSv4/flexfiles: Abort I/O early if the layout segment was invalidated"
  SUNRPC: Handle EADDRINUSE and ENOBUFS correctly
  pNFS/flexfiles: Turn off soft RPC calls
  SUNRPC: Don't handle errors if the bind/connect succeeded
  NFS: On fatal writeback errors, we need to call nfs_inode_remove_request()
  NFS: Fix initialisation of I/O result struct in nfs_pgio_rpcsetup
  NFS: Ensure O_DIRECT reports an error if the bytes read/written is 0
  NFSv4/pnfs: Fix a page lock leak in nfs_pageio_resend()
  NFSv4: Fix return value in nfs_finish_open()
  NFSv4: Fix return values for nfs4_file_open()
  NFS: Don't refresh attributes with mounted-on-file information
  • Loading branch information
Linus Torvalds committed Aug 27, 2019
2 parents 6525771 + 99300a8 commit 9e8312f
Show file tree
Hide file tree
Showing 14 changed files with 163 additions and 118 deletions.
2 changes: 1 addition & 1 deletion fs/nfs/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -1487,7 +1487,7 @@ static int nfs_finish_open(struct nfs_open_context *ctx,
if (S_ISREG(file->f_path.dentry->d_inode->i_mode))
nfs_file_set_open_context(file, ctx);
else
err = -ESTALE;
err = -EOPENSTALE;
out:
return err;
}
Expand Down
27 changes: 18 additions & 9 deletions fs/nfs/direct.c
Original file line number Diff line number Diff line change
Expand Up @@ -401,15 +401,21 @@ static void nfs_direct_read_completion(struct nfs_pgio_header *hdr)
unsigned long bytes = 0;
struct nfs_direct_req *dreq = hdr->dreq;

if (test_bit(NFS_IOHDR_REDO, &hdr->flags))
goto out_put;

spin_lock(&dreq->lock);
if (test_bit(NFS_IOHDR_ERROR, &hdr->flags) && (hdr->good_bytes == 0))
if (test_bit(NFS_IOHDR_ERROR, &hdr->flags))
dreq->error = hdr->error;
else

if (test_bit(NFS_IOHDR_REDO, &hdr->flags)) {
spin_unlock(&dreq->lock);
goto out_put;
}

if (hdr->good_bytes != 0)
nfs_direct_good_bytes(dreq, hdr);

if (test_bit(NFS_IOHDR_EOF, &hdr->flags))
dreq->error = 0;

spin_unlock(&dreq->lock);

while (!list_empty(&hdr->pages)) {
Expand Down Expand Up @@ -782,16 +788,19 @@ static void nfs_direct_write_completion(struct nfs_pgio_header *hdr)
bool request_commit = false;
struct nfs_page *req = nfs_list_entry(hdr->pages.next);

if (test_bit(NFS_IOHDR_REDO, &hdr->flags))
goto out_put;

nfs_init_cinfo_from_dreq(&cinfo, dreq);

spin_lock(&dreq->lock);

if (test_bit(NFS_IOHDR_ERROR, &hdr->flags))
dreq->error = hdr->error;
if (dreq->error == 0) {

if (test_bit(NFS_IOHDR_REDO, &hdr->flags)) {
spin_unlock(&dreq->lock);
goto out_put;
}

if (hdr->good_bytes != 0) {
nfs_direct_good_bytes(dreq, hdr);
if (nfs_write_need_commit(hdr)) {
if (dreq->flags == NFS_ODIRECT_RESCHED_WRITES)
Expand Down
28 changes: 9 additions & 19 deletions fs/nfs/flexfilelayout/flexfilelayout.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
*/

#include <linux/nfs_fs.h>
#include <linux/nfs_mount.h>
#include <linux/nfs_page.h>
#include <linux/module.h>
#include <linux/sched/mm.h>
Expand Down Expand Up @@ -928,7 +929,9 @@ ff_layout_pg_init_read(struct nfs_pageio_descriptor *pgio,
pgm = &pgio->pg_mirrors[0];
pgm->pg_bsize = mirror->mirror_ds->ds_versions[0].rsize;

pgio->pg_maxretrans = io_maxretrans;
if (NFS_SERVER(pgio->pg_inode)->flags &
(NFS_MOUNT_SOFT|NFS_MOUNT_SOFTERR))
pgio->pg_maxretrans = io_maxretrans;
return;
out_nolseg:
if (pgio->pg_error < 0)
Expand All @@ -940,6 +943,7 @@ ff_layout_pg_init_read(struct nfs_pageio_descriptor *pgio,
pgio->pg_lseg);
pnfs_put_lseg(pgio->pg_lseg);
pgio->pg_lseg = NULL;
pgio->pg_maxretrans = 0;
nfs_pageio_reset_read_mds(pgio);
}

Expand Down Expand Up @@ -1000,7 +1004,9 @@ ff_layout_pg_init_write(struct nfs_pageio_descriptor *pgio,
pgm->pg_bsize = mirror->mirror_ds->ds_versions[0].wsize;
}

pgio->pg_maxretrans = io_maxretrans;
if (NFS_SERVER(pgio->pg_inode)->flags &
(NFS_MOUNT_SOFT|NFS_MOUNT_SOFTERR))
pgio->pg_maxretrans = io_maxretrans;
return;

out_mds:
Expand All @@ -1010,6 +1016,7 @@ ff_layout_pg_init_write(struct nfs_pageio_descriptor *pgio,
pgio->pg_lseg);
pnfs_put_lseg(pgio->pg_lseg);
pgio->pg_lseg = NULL;
pgio->pg_maxretrans = 0;
nfs_pageio_reset_write_mds(pgio);
}

Expand Down Expand Up @@ -1148,8 +1155,6 @@ static int ff_layout_async_handle_error_v4(struct rpc_task *task,
break;
case -NFS4ERR_RETRY_UNCACHED_REP:
break;
case -EAGAIN:
return -NFS4ERR_RESET_TO_PNFS;
/* Invalidate Layout errors */
case -NFS4ERR_PNFS_NO_LAYOUT:
case -ESTALE: /* mapped NFS4ERR_STALE */
Expand Down Expand Up @@ -1210,7 +1215,6 @@ static int ff_layout_async_handle_error_v3(struct rpc_task *task,
case -EBADHANDLE:
case -ELOOP:
case -ENOSPC:
case -EAGAIN:
break;
case -EJUKEBOX:
nfs_inc_stats(lseg->pls_layout->plh_inode, NFSIOS_DELAY);
Expand Down Expand Up @@ -1445,16 +1449,6 @@ static void ff_layout_read_prepare_v4(struct rpc_task *task, void *data)
ff_layout_read_prepare_common(task, hdr);
}

static void
ff_layout_io_prepare_transmit(struct rpc_task *task,
void *data)
{
struct nfs_pgio_header *hdr = data;

if (!pnfs_is_valid_lseg(hdr->lseg))
rpc_exit(task, -EAGAIN);
}

static void ff_layout_read_call_done(struct rpc_task *task, void *data)
{
struct nfs_pgio_header *hdr = data;
Expand Down Expand Up @@ -1740,31 +1734,27 @@ static void ff_layout_commit_release(void *data)

static const struct rpc_call_ops ff_layout_read_call_ops_v3 = {
.rpc_call_prepare = ff_layout_read_prepare_v3,
.rpc_call_prepare_transmit = ff_layout_io_prepare_transmit,
.rpc_call_done = ff_layout_read_call_done,
.rpc_count_stats = ff_layout_read_count_stats,
.rpc_release = ff_layout_read_release,
};

static const struct rpc_call_ops ff_layout_read_call_ops_v4 = {
.rpc_call_prepare = ff_layout_read_prepare_v4,
.rpc_call_prepare_transmit = ff_layout_io_prepare_transmit,
.rpc_call_done = ff_layout_read_call_done,
.rpc_count_stats = ff_layout_read_count_stats,
.rpc_release = ff_layout_read_release,
};

static const struct rpc_call_ops ff_layout_write_call_ops_v3 = {
.rpc_call_prepare = ff_layout_write_prepare_v3,
.rpc_call_prepare_transmit = ff_layout_io_prepare_transmit,
.rpc_call_done = ff_layout_write_call_done,
.rpc_count_stats = ff_layout_write_count_stats,
.rpc_release = ff_layout_write_release,
};

static const struct rpc_call_ops ff_layout_write_call_ops_v4 = {
.rpc_call_prepare = ff_layout_write_prepare_v4,
.rpc_call_prepare_transmit = ff_layout_io_prepare_transmit,
.rpc_call_done = ff_layout_write_call_done,
.rpc_count_stats = ff_layout_write_count_stats,
.rpc_release = ff_layout_write_release,
Expand Down
33 changes: 19 additions & 14 deletions fs/nfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -1403,12 +1403,21 @@ static int nfs_check_inode_attributes(struct inode *inode, struct nfs_fattr *fat
if (NFS_PROTO(inode)->have_delegation(inode, FMODE_READ))
return 0;

/* No fileid? Just exit */
if (!(fattr->valid & NFS_ATTR_FATTR_FILEID))
return 0;
/* Has the inode gone and changed behind our back? */
if ((fattr->valid & NFS_ATTR_FATTR_FILEID) && nfsi->fileid != fattr->fileid)
if (nfsi->fileid != fattr->fileid) {
/* Is this perhaps the mounted-on fileid? */
if ((fattr->valid & NFS_ATTR_FATTR_MOUNTED_ON_FILEID) &&
nfsi->fileid == fattr->mounted_on_fileid)
return 0;
return -ESTALE;
}
if ((fattr->valid & NFS_ATTR_FATTR_TYPE) && (inode->i_mode & S_IFMT) != (fattr->mode & S_IFMT))
return -ESTALE;


if (!nfs_file_has_buffered_writers(nfsi)) {
/* Verify a few of the more important attributes */
if ((fattr->valid & NFS_ATTR_FATTR_CHANGE) != 0 && !inode_eq_iversion_raw(inode, fattr->change_attr))
Expand Down Expand Up @@ -1768,18 +1777,6 @@ int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fa
EXPORT_SYMBOL_GPL(nfs_post_op_update_inode_force_wcc);


static inline bool nfs_fileid_valid(struct nfs_inode *nfsi,
struct nfs_fattr *fattr)
{
bool ret1 = true, ret2 = true;

if (fattr->valid & NFS_ATTR_FATTR_FILEID)
ret1 = (nfsi->fileid == fattr->fileid);
if (fattr->valid & NFS_ATTR_FATTR_MOUNTED_ON_FILEID)
ret2 = (nfsi->fileid == fattr->mounted_on_fileid);
return ret1 || ret2;
}

/*
* Many nfs protocol calls return the new file attributes after
* an operation. Here we update the inode to reflect the state
Expand Down Expand Up @@ -1810,7 +1807,15 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
nfs_display_fhandle_hash(NFS_FH(inode)),
atomic_read(&inode->i_count), fattr->valid);

if (!nfs_fileid_valid(nfsi, fattr)) {
/* No fileid? Just exit */
if (!(fattr->valid & NFS_ATTR_FATTR_FILEID))
return 0;
/* Has the inode gone and changed behind our back? */
if (nfsi->fileid != fattr->fileid) {
/* Is this perhaps the mounted-on fileid? */
if ((fattr->valid & NFS_ATTR_FATTR_MOUNTED_ON_FILEID) &&
nfsi->fileid == fattr->mounted_on_fileid)
return 0;
printk(KERN_ERR "NFS: server %s error: fileid changed\n"
"fsid %s: expected fileid 0x%Lx, got 0x%Lx\n",
NFS_SERVER(inode)->nfs_client->cl_hostname,
Expand Down
10 changes: 10 additions & 0 deletions fs/nfs/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -775,3 +775,13 @@ static inline bool nfs_error_is_fatal(int err)
}
}

static inline bool nfs_error_is_fatal_on_server(int err)
{
switch (err) {
case 0:
case -ERESTARTSYS:
case -EINTR:
return false;
}
return nfs_error_is_fatal(err);
}
12 changes: 6 additions & 6 deletions fs/nfs/nfs4file.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,13 @@ nfs4_file_open(struct inode *inode, struct file *filp)
if (IS_ERR(inode)) {
err = PTR_ERR(inode);
switch (err) {
case -EPERM:
case -EACCES:
case -EDQUOT:
case -ENOSPC:
case -EROFS:
goto out_put_ctx;
default:
goto out_put_ctx;
case -ENOENT:
case -ESTALE:
case -EISDIR:
case -ENOTDIR:
case -ELOOP:
goto out_drop;
}
}
Expand Down
19 changes: 11 additions & 8 deletions fs/nfs/pagelist.c
Original file line number Diff line number Diff line change
Expand Up @@ -590,7 +590,7 @@ static void nfs_pgio_rpcsetup(struct nfs_pgio_header *hdr,
}

hdr->res.fattr = &hdr->fattr;
hdr->res.count = count;
hdr->res.count = 0;
hdr->res.eof = 0;
hdr->res.verf = &hdr->verf;
nfs_fattr_init(&hdr->fattr);
Expand Down Expand Up @@ -1251,20 +1251,23 @@ static void nfs_pageio_complete_mirror(struct nfs_pageio_descriptor *desc,
int nfs_pageio_resend(struct nfs_pageio_descriptor *desc,
struct nfs_pgio_header *hdr)
{
LIST_HEAD(failed);
LIST_HEAD(pages);

desc->pg_io_completion = hdr->io_completion;
desc->pg_dreq = hdr->dreq;
while (!list_empty(&hdr->pages)) {
struct nfs_page *req = nfs_list_entry(hdr->pages.next);
list_splice_init(&hdr->pages, &pages);
while (!list_empty(&pages)) {
struct nfs_page *req = nfs_list_entry(pages.next);

if (!nfs_pageio_add_request(desc, req))
nfs_list_move_request(req, &failed);
break;
}
nfs_pageio_complete(desc);
if (!list_empty(&failed)) {
list_move(&failed, &hdr->pages);
return desc->pg_error < 0 ? desc->pg_error : -EIO;
if (!list_empty(&pages)) {
int err = desc->pg_error < 0 ? desc->pg_error : -EIO;
hdr->completion_ops->error_cleanup(&pages, err);
nfs_set_pgio_error(hdr, err, hdr->io_start);
return err;
}
return 0;
}
Expand Down
15 changes: 10 additions & 5 deletions fs/nfs/pnfs_nfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -627,11 +627,16 @@ static int _nfs4_pnfs_v3_ds_connect(struct nfs_server *mds_srv,
/* Add this address as an alias */
rpc_clnt_add_xprt(clp->cl_rpcclient, &xprt_args,
rpc_clnt_test_and_add_xprt, NULL);
} else
clp = get_v3_ds_connect(mds_srv,
(struct sockaddr *)&da->da_addr,
da->da_addrlen, IPPROTO_TCP,
timeo, retrans);
continue;
}
clp = get_v3_ds_connect(mds_srv,
(struct sockaddr *)&da->da_addr,
da->da_addrlen, IPPROTO_TCP,
timeo, retrans);
if (IS_ERR(clp))
continue;
clp->cl_rpcclient->cl_softerr = 0;
clp->cl_rpcclient->cl_softrtry = 0;
}

if (IS_ERR(clp)) {
Expand Down
7 changes: 5 additions & 2 deletions fs/nfs/proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -594,7 +594,8 @@ static int nfs_read_done(struct rpc_task *task, struct nfs_pgio_header *hdr)
/* Emulate the eof flag, which isn't normally needed in NFSv2
* as it is guaranteed to always return the file attributes
*/
if (hdr->args.offset + hdr->res.count >= hdr->res.fattr->size)
if ((hdr->res.count == 0 && hdr->args.count > 0) ||
hdr->args.offset + hdr->res.count >= hdr->res.fattr->size)
hdr->res.eof = 1;
}
return 0;
Expand All @@ -615,8 +616,10 @@ static int nfs_proc_pgio_rpc_prepare(struct rpc_task *task,

static int nfs_write_done(struct rpc_task *task, struct nfs_pgio_header *hdr)
{
if (task->tk_status >= 0)
if (task->tk_status >= 0) {
hdr->res.count = hdr->args.count;
nfs_writeback_update_inode(hdr);
}
return 0;
}

Expand Down
Loading

0 comments on commit 9e8312f

Please sign in to comment.