Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9e8312f5 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
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
parents 6525771f 99300a85
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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;
}
+18 −9
Original line number Diff line number Diff line
@@ -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)) {
@@ -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)
+9 −19
Original line number Diff line number Diff line
@@ -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>
@@ -928,6 +929,8 @@ 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;

	if (NFS_SERVER(pgio->pg_inode)->flags &
			(NFS_MOUNT_SOFT|NFS_MOUNT_SOFTERR))
		pgio->pg_maxretrans = io_maxretrans;
	return;
out_nolseg:
@@ -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);
}

@@ -1000,6 +1004,8 @@ ff_layout_pg_init_write(struct nfs_pageio_descriptor *pgio,
		pgm->pg_bsize = mirror->mirror_ds->ds_versions[0].wsize;
	}

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

@@ -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);
}

@@ -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 */
@@ -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);
@@ -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;
@@ -1740,7 +1734,6 @@ 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,
@@ -1748,7 +1741,6 @@ static const struct rpc_call_ops ff_layout_read_call_ops_v3 = {

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,
@@ -1756,7 +1748,6 @@ static const struct rpc_call_ops ff_layout_read_call_ops_v4 = {

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,
@@ -1764,7 +1755,6 @@ static const struct rpc_call_ops ff_layout_write_call_ops_v3 = {

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,
+19 −14
Original line number Diff line number Diff line
@@ -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))
@@ -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
@@ -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,
+10 −0
Original line number Diff line number Diff line
@@ -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);
}
Loading