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

Commit 8003a573 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull NFS client bugfixes from Trond Myklebust:
 "Highlights include:

  Stable patches:
   - Fix a NFSv4 callback identifier leak that was also causing client
     crashes
   - Fix NFSv4 callback decoding issues when incoming requests are
     truncated
   - Don't declare the attribute cache valid when we call
     nfs_update_inode with an empty attribute structure.
   - Resend LAYOUTGET when there is a race that changes the seqid

  Bugfixes:
   - Fix a number of issues with the NFSv4.2 CLONE ioctl()
   - Properly set NFS v4.2 NFSDBG_FACILITY
   - NFSv4 referrals are broken; Cleanup FATTR4_WORD0_FS_LOCATIONS after
     decoding success
   - Use sliding delay when LAYOUTGET gets NFS4ERR_DELAY
   - Ensure that attrcache is revalidated after a SETATTR"

* tag 'nfs-for-4.4-2' of git://git.linux-nfs.org/projects/trondmy/linux-nfs:
  nfs4: resend LAYOUTGET when there is a race that changes the seqid
  nfs: if we have no valid attrs, then don't declare the attribute cache valid
  nfs: ensure that attrcache is revalidated after a SETATTR
  nfs4: limit callback decoding to received bytes
  nfs4: start callback_ident at idr 1
  nfs: use sliding delay when LAYOUTGET gets NFS4ERR_DELAY
  NFS4: Cleanup FATTR4_WORD0_FS_LOCATIONS after decoding success
  NFS: Properly set NFS v4.2 NFSDBG_FACILITY
  nfs: reduce the amount of ifdefs for v4.2 in nfs4file.c
  nfs: use btrfs ioctl defintions for clone
  nfs: allow intra-file CLONE
  nfs: offer native ioctls even if CONFIG_COMPAT is set
  nfs: pass on count for CLONE operations
parents d0bc387d 4f2e9dce
Loading
Loading
Loading
Loading
+5 −2
Original line number Diff line number Diff line
@@ -78,7 +78,8 @@ static __be32 *read_buf(struct xdr_stream *xdr, int nbytes)

	p = xdr_inline_decode(xdr, nbytes);
	if (unlikely(p == NULL))
		printk(KERN_WARNING "NFS: NFSv4 callback reply buffer overflowed!\n");
		printk(KERN_WARNING "NFS: NFSv4 callback reply buffer overflowed "
							"or truncated request.\n");
	return p;
}

@@ -889,6 +890,7 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r
	struct cb_compound_hdr_arg hdr_arg = { 0 };
	struct cb_compound_hdr_res hdr_res = { NULL };
	struct xdr_stream xdr_in, xdr_out;
	struct xdr_buf *rq_arg = &rqstp->rq_arg;
	__be32 *p, status;
	struct cb_process_state cps = {
		.drc_status = 0,
@@ -900,7 +902,8 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r

	dprintk("%s: start\n", __func__);

	xdr_init_decode(&xdr_in, &rqstp->rq_arg, rqstp->rq_arg.head[0].iov_base);
	rq_arg->len = rq_arg->head[0].iov_len + rq_arg->page_len;
	xdr_init_decode(&xdr_in, rq_arg, rq_arg->head[0].iov_base);

	p = (__be32*)((char *)rqstp->rq_res.head[0].iov_base + rqstp->rq_res.head[0].iov_len);
	xdr_init_encode(&xdr_out, &rqstp->rq_res, p);
+9 −2
Original line number Diff line number Diff line
@@ -618,7 +618,10 @@ void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr,
		nfs_inc_stats(inode, NFSIOS_SETATTRTRUNC);
		nfs_vmtruncate(inode, attr->ia_size);
	}
	if (fattr->valid)
		nfs_update_inode(inode, fattr);
	else
		NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ATTR;
	spin_unlock(&inode->i_lock);
}
EXPORT_SYMBOL_GPL(nfs_setattr_update_inode);
@@ -1824,7 +1827,11 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
		if ((long)fattr->gencount - (long)nfsi->attr_gencount > 0)
			nfsi->attr_gencount = fattr->gencount;
	}

	/* Don't declare attrcache up to date if there were no attrs! */
	if (fattr->valid != 0)
		invalid &= ~NFS_INO_INVALID_ATTR;

	/* Don't invalidate the data if we were to blame */
	if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode)
				|| S_ISLNK(inode->i_mode)))
+2 −1
Original line number Diff line number Diff line
@@ -14,7 +14,7 @@
#include "pnfs.h"
#include "internal.h"

#define NFSDBG_FACILITY NFSDBG_PNFS
#define NFSDBG_FACILITY NFSDBG_PROC

static int nfs42_set_rw_stateid(nfs4_stateid *dst, struct file *file,
				fmode_t fmode)
@@ -284,6 +284,7 @@ static int _nfs42_proc_clone(struct rpc_message *msg, struct file *src_f,
		.dst_fh = NFS_FH(dst_inode),
		.src_offset = src_offset,
		.dst_offset = dst_offset,
		.count = count,
		.dst_bitmask = server->cache_consistency_bitmask,
	};
	struct nfs42_clone_res res = {
+1 −1
Original line number Diff line number Diff line
@@ -33,7 +33,7 @@ static int nfs_get_cb_ident_idr(struct nfs_client *clp, int minorversion)
		return ret;
	idr_preload(GFP_KERNEL);
	spin_lock(&nn->nfs_client_lock);
	ret = idr_alloc(&nn->cb_ident_idr, clp, 0, 0, GFP_NOWAIT);
	ret = idr_alloc(&nn->cb_ident_idr, clp, 1, 0, GFP_NOWAIT);
	if (ret >= 0)
		clp->cl_cb_ident = ret;
	spin_unlock(&nn->nfs_client_lock);
+27 −32
Original line number Diff line number Diff line
@@ -7,6 +7,7 @@
#include <linux/file.h>
#include <linux/falloc.h>
#include <linux/nfs_fs.h>
#include <uapi/linux/btrfs.h>	/* BTRFS_IOC_CLONE/BTRFS_IOC_CLONE_RANGE */
#include "delegation.h"
#include "internal.h"
#include "iostat.h"
@@ -203,6 +204,7 @@ nfs42_ioctl_clone(struct file *dst_file, unsigned long srcfd,
	struct fd src_file;
	struct inode *src_inode;
	unsigned int bs = server->clone_blksize;
	bool same_inode = false;
	int ret;

	/* dst file must be opened for writing */
@@ -221,10 +223,8 @@ nfs42_ioctl_clone(struct file *dst_file, unsigned long srcfd,

	src_inode = file_inode(src_file.file);

	/* src and dst must be different files */
	ret = -EINVAL;
	if (src_inode == dst_inode)
		goto out_fput;
		same_inode = true;

	/* src file must be opened for reading */
	if (!(src_file.file->f_mode & FMODE_READ))
@@ -249,8 +249,16 @@ nfs42_ioctl_clone(struct file *dst_file, unsigned long srcfd,
			goto out_fput;
	}

	/* verify if ranges are overlapped within the same file */
	if (same_inode) {
		if (dst_off + count > src_off && dst_off < src_off + count)
			goto out_fput;
	}

	/* XXX: do we lock at all? what if server needs CB_RECALL_LAYOUT? */
	if (dst_inode < src_inode) {
	if (same_inode) {
		mutex_lock(&src_inode->i_mutex);
	} else if (dst_inode < src_inode) {
		mutex_lock_nested(&dst_inode->i_mutex, I_MUTEX_PARENT);
		mutex_lock_nested(&src_inode->i_mutex, I_MUTEX_CHILD);
	} else {
@@ -275,7 +283,9 @@ nfs42_ioctl_clone(struct file *dst_file, unsigned long srcfd,
		truncate_inode_pages_range(&dst_inode->i_data, dst_off, dst_off + count - 1);

out_unlock:
	if (dst_inode < src_inode) {
	if (same_inode) {
		mutex_unlock(&src_inode->i_mutex);
	} else if (dst_inode < src_inode) {
		mutex_unlock(&src_inode->i_mutex);
		mutex_unlock(&dst_inode->i_mutex);
	} else {
@@ -291,46 +301,31 @@ nfs42_ioctl_clone(struct file *dst_file, unsigned long srcfd,

static long nfs42_ioctl_clone_range(struct file *dst_file, void __user *argp)
{
	struct nfs_ioctl_clone_range_args args;
	struct btrfs_ioctl_clone_range_args args;

	if (copy_from_user(&args, argp, sizeof(args)))
		return -EFAULT;

	return nfs42_ioctl_clone(dst_file, args.src_fd, args.src_off, args.dst_off, args.count);
	return nfs42_ioctl_clone(dst_file, args.src_fd, args.src_offset,
				 args.dest_offset, args.src_length);
}
#else
static long nfs42_ioctl_clone(struct file *dst_file, unsigned long srcfd,
		u64 src_off, u64 dst_off, u64 count)
{
	return -ENOTTY;
}

static long nfs42_ioctl_clone_range(struct file *dst_file, void __user *argp)
{
	return -ENOTTY;
}
#endif /* CONFIG_NFS_V4_2 */

long nfs4_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
	void __user *argp = (void __user *)arg;

	switch (cmd) {
	case NFS_IOC_CLONE:
	case BTRFS_IOC_CLONE:
		return nfs42_ioctl_clone(file, arg, 0, 0, 0);
	case NFS_IOC_CLONE_RANGE:
	case BTRFS_IOC_CLONE_RANGE:
		return nfs42_ioctl_clone_range(file, argp);
	}

	return -ENOTTY;
}
#endif /* CONFIG_NFS_V4_2 */

const struct file_operations nfs4_file_operations = {
#ifdef CONFIG_NFS_V4_2
	.llseek		= nfs4_file_llseek,
#else
	.llseek		= nfs_file_llseek,
#endif
	.read_iter	= nfs_file_read,
	.write_iter	= nfs_file_write,
	.mmap		= nfs_file_mmap,
@@ -342,14 +337,14 @@ const struct file_operations nfs4_file_operations = {
	.flock		= nfs_flock,
	.splice_read	= nfs_file_splice_read,
	.splice_write	= iter_file_splice_write,
#ifdef CONFIG_NFS_V4_2
	.fallocate	= nfs42_fallocate,
#endif /* CONFIG_NFS_V4_2 */
	.check_flags	= nfs_check_flags,
	.setlease	= simple_nosetlease,
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NFS_V4_2
	.llseek		= nfs4_file_llseek,
	.fallocate	= nfs42_fallocate,
	.unlocked_ioctl = nfs4_ioctl,
#else
	.compat_ioctl	= nfs4_ioctl,
#endif /* CONFIG_COMPAT */
#else
	.llseek		= nfs_file_llseek,
#endif
};
Loading