aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2015-11-27 20:22:47 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2015-11-27 20:22:47 -0500
commit8003a573560ae96540bce2a698347c6d502e2997 (patch)
treedd75a298d9659359a3dfc1b453881ac0312e93b7
parentd0bc387dbe7f93b5608e1d305a18f50060de69cb (diff)
parent4f2e9dce0c6348a95eaa56ade9bab18572221088 (diff)
Merge tag 'nfs-for-4.4-2' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
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
-rw-r--r--fs/nfs/callback_xdr.c7
-rw-r--r--fs/nfs/inode.c11
-rw-r--r--fs/nfs/nfs42proc.c3
-rw-r--r--fs/nfs/nfs4client.c2
-rw-r--r--fs/nfs/nfs4file.c59
-rw-r--r--fs/nfs/nfs4proc.c2
-rw-r--r--fs/nfs/nfs4xdr.c1
-rw-r--r--fs/nfs/pnfs.c56
-rw-r--r--include/linux/nfs_xdr.h1
-rw-r--r--include/uapi/linux/nfs.h11
-rw-r--r--net/sunrpc/backchannel_rqst.c8
-rw-r--r--net/sunrpc/svc.c1
12 files changed, 87 insertions, 75 deletions
diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c
index 646cdac73488..beac58b0e09c 100644
--- a/fs/nfs/callback_xdr.c
+++ b/fs/nfs/callback_xdr.c
@@ -78,7 +78,8 @@ static __be32 *read_buf(struct xdr_stream *xdr, int nbytes)
78 78
79 p = xdr_inline_decode(xdr, nbytes); 79 p = xdr_inline_decode(xdr, nbytes);
80 if (unlikely(p == NULL)) 80 if (unlikely(p == NULL))
81 printk(KERN_WARNING "NFS: NFSv4 callback reply buffer overflowed!\n"); 81 printk(KERN_WARNING "NFS: NFSv4 callback reply buffer overflowed "
82 "or truncated request.\n");
82 return p; 83 return p;
83} 84}
84 85
@@ -889,6 +890,7 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r
889 struct cb_compound_hdr_arg hdr_arg = { 0 }; 890 struct cb_compound_hdr_arg hdr_arg = { 0 };
890 struct cb_compound_hdr_res hdr_res = { NULL }; 891 struct cb_compound_hdr_res hdr_res = { NULL };
891 struct xdr_stream xdr_in, xdr_out; 892 struct xdr_stream xdr_in, xdr_out;
893 struct xdr_buf *rq_arg = &rqstp->rq_arg;
892 __be32 *p, status; 894 __be32 *p, status;
893 struct cb_process_state cps = { 895 struct cb_process_state cps = {
894 .drc_status = 0, 896 .drc_status = 0,
@@ -900,7 +902,8 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r
900 902
901 dprintk("%s: start\n", __func__); 903 dprintk("%s: start\n", __func__);
902 904
903 xdr_init_decode(&xdr_in, &rqstp->rq_arg, rqstp->rq_arg.head[0].iov_base); 905 rq_arg->len = rq_arg->head[0].iov_len + rq_arg->page_len;
906 xdr_init_decode(&xdr_in, rq_arg, rq_arg->head[0].iov_base);
904 907
905 p = (__be32*)((char *)rqstp->rq_res.head[0].iov_base + rqstp->rq_res.head[0].iov_len); 908 p = (__be32*)((char *)rqstp->rq_res.head[0].iov_base + rqstp->rq_res.head[0].iov_len);
906 xdr_init_encode(&xdr_out, &rqstp->rq_res, p); 909 xdr_init_encode(&xdr_out, &rqstp->rq_res, p);
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 326d9e10d833..31b0a52223a7 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -618,7 +618,10 @@ void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr,
618 nfs_inc_stats(inode, NFSIOS_SETATTRTRUNC); 618 nfs_inc_stats(inode, NFSIOS_SETATTRTRUNC);
619 nfs_vmtruncate(inode, attr->ia_size); 619 nfs_vmtruncate(inode, attr->ia_size);
620 } 620 }
621 nfs_update_inode(inode, fattr); 621 if (fattr->valid)
622 nfs_update_inode(inode, fattr);
623 else
624 NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ATTR;
622 spin_unlock(&inode->i_lock); 625 spin_unlock(&inode->i_lock);
623} 626}
624EXPORT_SYMBOL_GPL(nfs_setattr_update_inode); 627EXPORT_SYMBOL_GPL(nfs_setattr_update_inode);
@@ -1824,7 +1827,11 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
1824 if ((long)fattr->gencount - (long)nfsi->attr_gencount > 0) 1827 if ((long)fattr->gencount - (long)nfsi->attr_gencount > 0)
1825 nfsi->attr_gencount = fattr->gencount; 1828 nfsi->attr_gencount = fattr->gencount;
1826 } 1829 }
1827 invalid &= ~NFS_INO_INVALID_ATTR; 1830
1831 /* Don't declare attrcache up to date if there were no attrs! */
1832 if (fattr->valid != 0)
1833 invalid &= ~NFS_INO_INVALID_ATTR;
1834
1828 /* Don't invalidate the data if we were to blame */ 1835 /* Don't invalidate the data if we were to blame */
1829 if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) 1836 if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode)
1830 || S_ISLNK(inode->i_mode))) 1837 || S_ISLNK(inode->i_mode)))
diff --git a/fs/nfs/nfs42proc.c b/fs/nfs/nfs42proc.c
index 3e92a3cde15d..6b1ce9825430 100644
--- a/fs/nfs/nfs42proc.c
+++ b/fs/nfs/nfs42proc.c
@@ -14,7 +14,7 @@
14#include "pnfs.h" 14#include "pnfs.h"
15#include "internal.h" 15#include "internal.h"
16 16
17#define NFSDBG_FACILITY NFSDBG_PNFS 17#define NFSDBG_FACILITY NFSDBG_PROC
18 18
19static int nfs42_set_rw_stateid(nfs4_stateid *dst, struct file *file, 19static int nfs42_set_rw_stateid(nfs4_stateid *dst, struct file *file,
20 fmode_t fmode) 20 fmode_t fmode)
@@ -284,6 +284,7 @@ static int _nfs42_proc_clone(struct rpc_message *msg, struct file *src_f,
284 .dst_fh = NFS_FH(dst_inode), 284 .dst_fh = NFS_FH(dst_inode),
285 .src_offset = src_offset, 285 .src_offset = src_offset,
286 .dst_offset = dst_offset, 286 .dst_offset = dst_offset,
287 .count = count,
287 .dst_bitmask = server->cache_consistency_bitmask, 288 .dst_bitmask = server->cache_consistency_bitmask,
288 }; 289 };
289 struct nfs42_clone_res res = { 290 struct nfs42_clone_res res = {
diff --git a/fs/nfs/nfs4client.c b/fs/nfs/nfs4client.c
index 223bedda64ae..10410e8b5853 100644
--- a/fs/nfs/nfs4client.c
+++ b/fs/nfs/nfs4client.c
@@ -33,7 +33,7 @@ static int nfs_get_cb_ident_idr(struct nfs_client *clp, int minorversion)
33 return ret; 33 return ret;
34 idr_preload(GFP_KERNEL); 34 idr_preload(GFP_KERNEL);
35 spin_lock(&nn->nfs_client_lock); 35 spin_lock(&nn->nfs_client_lock);
36 ret = idr_alloc(&nn->cb_ident_idr, clp, 0, 0, GFP_NOWAIT); 36 ret = idr_alloc(&nn->cb_ident_idr, clp, 1, 0, GFP_NOWAIT);
37 if (ret >= 0) 37 if (ret >= 0)
38 clp->cl_cb_ident = ret; 38 clp->cl_cb_ident = ret;
39 spin_unlock(&nn->nfs_client_lock); 39 spin_unlock(&nn->nfs_client_lock);
diff --git a/fs/nfs/nfs4file.c b/fs/nfs/nfs4file.c
index 4aa571956cd6..db9b5fea5b3e 100644
--- a/fs/nfs/nfs4file.c
+++ b/fs/nfs/nfs4file.c
@@ -7,6 +7,7 @@
7#include <linux/file.h> 7#include <linux/file.h>
8#include <linux/falloc.h> 8#include <linux/falloc.h>
9#include <linux/nfs_fs.h> 9#include <linux/nfs_fs.h>
10#include <uapi/linux/btrfs.h> /* BTRFS_IOC_CLONE/BTRFS_IOC_CLONE_RANGE */
10#include "delegation.h" 11#include "delegation.h"
11#include "internal.h" 12#include "internal.h"
12#include "iostat.h" 13#include "iostat.h"
@@ -203,6 +204,7 @@ nfs42_ioctl_clone(struct file *dst_file, unsigned long srcfd,
203 struct fd src_file; 204 struct fd src_file;
204 struct inode *src_inode; 205 struct inode *src_inode;
205 unsigned int bs = server->clone_blksize; 206 unsigned int bs = server->clone_blksize;
207 bool same_inode = false;
206 int ret; 208 int ret;
207 209
208 /* dst file must be opened for writing */ 210 /* dst file must be opened for writing */
@@ -221,10 +223,8 @@ nfs42_ioctl_clone(struct file *dst_file, unsigned long srcfd,
221 223
222 src_inode = file_inode(src_file.file); 224 src_inode = file_inode(src_file.file);
223 225
224 /* src and dst must be different files */
225 ret = -EINVAL;
226 if (src_inode == dst_inode) 226 if (src_inode == dst_inode)
227 goto out_fput; 227 same_inode = true;
228 228
229 /* src file must be opened for reading */ 229 /* src file must be opened for reading */
230 if (!(src_file.file->f_mode & FMODE_READ)) 230 if (!(src_file.file->f_mode & FMODE_READ))
@@ -249,8 +249,16 @@ nfs42_ioctl_clone(struct file *dst_file, unsigned long srcfd,
249 goto out_fput; 249 goto out_fput;
250 } 250 }
251 251
252 /* verify if ranges are overlapped within the same file */
253 if (same_inode) {
254 if (dst_off + count > src_off && dst_off < src_off + count)
255 goto out_fput;
256 }
257
252 /* XXX: do we lock at all? what if server needs CB_RECALL_LAYOUT? */ 258 /* XXX: do we lock at all? what if server needs CB_RECALL_LAYOUT? */
253 if (dst_inode < src_inode) { 259 if (same_inode) {
260 mutex_lock(&src_inode->i_mutex);
261 } else if (dst_inode < src_inode) {
254 mutex_lock_nested(&dst_inode->i_mutex, I_MUTEX_PARENT); 262 mutex_lock_nested(&dst_inode->i_mutex, I_MUTEX_PARENT);
255 mutex_lock_nested(&src_inode->i_mutex, I_MUTEX_CHILD); 263 mutex_lock_nested(&src_inode->i_mutex, I_MUTEX_CHILD);
256 } else { 264 } else {
@@ -275,7 +283,9 @@ nfs42_ioctl_clone(struct file *dst_file, unsigned long srcfd,
275 truncate_inode_pages_range(&dst_inode->i_data, dst_off, dst_off + count - 1); 283 truncate_inode_pages_range(&dst_inode->i_data, dst_off, dst_off + count - 1);
276 284
277out_unlock: 285out_unlock:
278 if (dst_inode < src_inode) { 286 if (same_inode) {
287 mutex_unlock(&src_inode->i_mutex);
288 } else if (dst_inode < src_inode) {
279 mutex_unlock(&src_inode->i_mutex); 289 mutex_unlock(&src_inode->i_mutex);
280 mutex_unlock(&dst_inode->i_mutex); 290 mutex_unlock(&dst_inode->i_mutex);
281 } else { 291 } else {
@@ -291,46 +301,31 @@ out_drop_write:
291 301
292static long nfs42_ioctl_clone_range(struct file *dst_file, void __user *argp) 302static long nfs42_ioctl_clone_range(struct file *dst_file, void __user *argp)
293{ 303{
294 struct nfs_ioctl_clone_range_args args; 304 struct btrfs_ioctl_clone_range_args args;
295 305
296 if (copy_from_user(&args, argp, sizeof(args))) 306 if (copy_from_user(&args, argp, sizeof(args)))
297 return -EFAULT; 307 return -EFAULT;
298 308
299 return nfs42_ioctl_clone(dst_file, args.src_fd, args.src_off, args.dst_off, args.count); 309 return nfs42_ioctl_clone(dst_file, args.src_fd, args.src_offset,
300} 310 args.dest_offset, args.src_length);
301#else
302static long nfs42_ioctl_clone(struct file *dst_file, unsigned long srcfd,
303 u64 src_off, u64 dst_off, u64 count)
304{
305 return -ENOTTY;
306}
307
308static long nfs42_ioctl_clone_range(struct file *dst_file, void __user *argp)
309{
310 return -ENOTTY;
311} 311}
312#endif /* CONFIG_NFS_V4_2 */
313 312
314long nfs4_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 313long nfs4_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
315{ 314{
316 void __user *argp = (void __user *)arg; 315 void __user *argp = (void __user *)arg;
317 316
318 switch (cmd) { 317 switch (cmd) {
319 case NFS_IOC_CLONE: 318 case BTRFS_IOC_CLONE:
320 return nfs42_ioctl_clone(file, arg, 0, 0, 0); 319 return nfs42_ioctl_clone(file, arg, 0, 0, 0);
321 case NFS_IOC_CLONE_RANGE: 320 case BTRFS_IOC_CLONE_RANGE:
322 return nfs42_ioctl_clone_range(file, argp); 321 return nfs42_ioctl_clone_range(file, argp);
323 } 322 }
324 323
325 return -ENOTTY; 324 return -ENOTTY;
326} 325}
326#endif /* CONFIG_NFS_V4_2 */
327 327
328const struct file_operations nfs4_file_operations = { 328const struct file_operations nfs4_file_operations = {
329#ifdef CONFIG_NFS_V4_2
330 .llseek = nfs4_file_llseek,
331#else
332 .llseek = nfs_file_llseek,
333#endif
334 .read_iter = nfs_file_read, 329 .read_iter = nfs_file_read,
335 .write_iter = nfs_file_write, 330 .write_iter = nfs_file_write,
336 .mmap = nfs_file_mmap, 331 .mmap = nfs_file_mmap,
@@ -342,14 +337,14 @@ const struct file_operations nfs4_file_operations = {
342 .flock = nfs_flock, 337 .flock = nfs_flock,
343 .splice_read = nfs_file_splice_read, 338 .splice_read = nfs_file_splice_read,
344 .splice_write = iter_file_splice_write, 339 .splice_write = iter_file_splice_write,
345#ifdef CONFIG_NFS_V4_2
346 .fallocate = nfs42_fallocate,
347#endif /* CONFIG_NFS_V4_2 */
348 .check_flags = nfs_check_flags, 340 .check_flags = nfs_check_flags,
349 .setlease = simple_nosetlease, 341 .setlease = simple_nosetlease,
350#ifdef CONFIG_COMPAT 342#ifdef CONFIG_NFS_V4_2
343 .llseek = nfs4_file_llseek,
344 .fallocate = nfs42_fallocate,
351 .unlocked_ioctl = nfs4_ioctl, 345 .unlocked_ioctl = nfs4_ioctl,
352#else
353 .compat_ioctl = nfs4_ioctl, 346 .compat_ioctl = nfs4_ioctl,
354#endif /* CONFIG_COMPAT */ 347#else
348 .llseek = nfs_file_llseek,
349#endif
355}; 350};
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 765a03559363..89818036f035 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -7866,7 +7866,7 @@ static void nfs4_layoutget_done(struct rpc_task *task, void *calldata)
7866 spin_unlock(&inode->i_lock); 7866 spin_unlock(&inode->i_lock);
7867 goto out_restart; 7867 goto out_restart;
7868 } 7868 }
7869 if (nfs4_async_handle_error(task, server, state, NULL) == -EAGAIN) 7869 if (nfs4_async_handle_error(task, server, state, &lgp->timeout) == -EAGAIN)
7870 goto out_restart; 7870 goto out_restart;
7871out: 7871out:
7872 dprintk("<-- %s\n", __func__); 7872 dprintk("<-- %s\n", __func__);
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index dfed4f5c8fcc..4e4441216804 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -3615,6 +3615,7 @@ static int decode_attr_fs_locations(struct xdr_stream *xdr, uint32_t *bitmap, st
3615 status = 0; 3615 status = 0;
3616 if (unlikely(!(bitmap[0] & FATTR4_WORD0_FS_LOCATIONS))) 3616 if (unlikely(!(bitmap[0] & FATTR4_WORD0_FS_LOCATIONS)))
3617 goto out; 3617 goto out;
3618 bitmap[0] &= ~FATTR4_WORD0_FS_LOCATIONS;
3618 status = -EIO; 3619 status = -EIO;
3619 /* Ignore borken servers that return unrequested attrs */ 3620 /* Ignore borken servers that return unrequested attrs */
3620 if (unlikely(res == NULL)) 3621 if (unlikely(res == NULL))
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c
index 93496c059837..5a8ae2125b50 100644
--- a/fs/nfs/pnfs.c
+++ b/fs/nfs/pnfs.c
@@ -872,33 +872,38 @@ send_layoutget(struct pnfs_layout_hdr *lo,
872 872
873 dprintk("--> %s\n", __func__); 873 dprintk("--> %s\n", __func__);
874 874
875 lgp = kzalloc(sizeof(*lgp), gfp_flags); 875 /*
876 if (lgp == NULL) 876 * Synchronously retrieve layout information from server and
877 return NULL; 877 * store in lseg. If we race with a concurrent seqid morphing
878 * op, then re-send the LAYOUTGET.
879 */
880 do {
881 lgp = kzalloc(sizeof(*lgp), gfp_flags);
882 if (lgp == NULL)
883 return NULL;
884
885 i_size = i_size_read(ino);
886
887 lgp->args.minlength = PAGE_CACHE_SIZE;
888 if (lgp->args.minlength > range->length)
889 lgp->args.minlength = range->length;
890 if (range->iomode == IOMODE_READ) {
891 if (range->offset >= i_size)
892 lgp->args.minlength = 0;
893 else if (i_size - range->offset < lgp->args.minlength)
894 lgp->args.minlength = i_size - range->offset;
895 }
896 lgp->args.maxcount = PNFS_LAYOUT_MAXSIZE;
897 lgp->args.range = *range;
898 lgp->args.type = server->pnfs_curr_ld->id;
899 lgp->args.inode = ino;
900 lgp->args.ctx = get_nfs_open_context(ctx);
901 lgp->gfp_flags = gfp_flags;
902 lgp->cred = lo->plh_lc_cred;
878 903
879 i_size = i_size_read(ino); 904 lseg = nfs4_proc_layoutget(lgp, gfp_flags);
905 } while (lseg == ERR_PTR(-EAGAIN));
880 906
881 lgp->args.minlength = PAGE_CACHE_SIZE;
882 if (lgp->args.minlength > range->length)
883 lgp->args.minlength = range->length;
884 if (range->iomode == IOMODE_READ) {
885 if (range->offset >= i_size)
886 lgp->args.minlength = 0;
887 else if (i_size - range->offset < lgp->args.minlength)
888 lgp->args.minlength = i_size - range->offset;
889 }
890 lgp->args.maxcount = PNFS_LAYOUT_MAXSIZE;
891 lgp->args.range = *range;
892 lgp->args.type = server->pnfs_curr_ld->id;
893 lgp->args.inode = ino;
894 lgp->args.ctx = get_nfs_open_context(ctx);
895 lgp->gfp_flags = gfp_flags;
896 lgp->cred = lo->plh_lc_cred;
897
898 /* Synchronously retrieve layout information from server and
899 * store in lseg.
900 */
901 lseg = nfs4_proc_layoutget(lgp, gfp_flags);
902 if (IS_ERR(lseg)) { 907 if (IS_ERR(lseg)) {
903 switch (PTR_ERR(lseg)) { 908 switch (PTR_ERR(lseg)) {
904 case -ENOMEM: 909 case -ENOMEM:
@@ -1687,6 +1692,7 @@ pnfs_layout_process(struct nfs4_layoutget *lgp)
1687 /* existing state ID, make sure the sequence number matches. */ 1692 /* existing state ID, make sure the sequence number matches. */
1688 if (pnfs_layout_stateid_blocked(lo, &res->stateid)) { 1693 if (pnfs_layout_stateid_blocked(lo, &res->stateid)) {
1689 dprintk("%s forget reply due to sequence\n", __func__); 1694 dprintk("%s forget reply due to sequence\n", __func__);
1695 status = -EAGAIN;
1690 goto out_forget_reply; 1696 goto out_forget_reply;
1691 } 1697 }
1692 pnfs_set_layout_stateid(lo, &res->stateid, false); 1698 pnfs_set_layout_stateid(lo, &res->stateid, false);
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index 570d630f98ae..11bbae44f4cb 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -251,6 +251,7 @@ struct nfs4_layoutget {
251 struct nfs4_layoutget_res res; 251 struct nfs4_layoutget_res res;
252 struct rpc_cred *cred; 252 struct rpc_cred *cred;
253 gfp_t gfp_flags; 253 gfp_t gfp_flags;
254 long timeout;
254}; 255};
255 256
256struct nfs4_getdeviceinfo_args { 257struct nfs4_getdeviceinfo_args {
diff --git a/include/uapi/linux/nfs.h b/include/uapi/linux/nfs.h
index 654bae3f1a38..5e6296160361 100644
--- a/include/uapi/linux/nfs.h
+++ b/include/uapi/linux/nfs.h
@@ -33,17 +33,6 @@
33 33
34#define NFS_PIPE_DIRNAME "nfs" 34#define NFS_PIPE_DIRNAME "nfs"
35 35
36/* NFS ioctls */
37/* Let's follow btrfs lead on CLONE to avoid messing userspace */
38#define NFS_IOC_CLONE _IOW(0x94, 9, int)
39#define NFS_IOC_CLONE_RANGE _IOW(0x94, 13, int)
40
41struct nfs_ioctl_clone_range_args {
42 __s64 src_fd;
43 __u64 src_off, count;
44 __u64 dst_off;
45};
46
47/* 36/*
48 * NFS stats. The good thing with these values is that NFSv3 errors are 37 * NFS stats. The good thing with these values is that NFSv3 errors are
49 * a superset of NFSv2 errors (with the exception of NFSERR_WFLUSH which 38 * a superset of NFSv2 errors (with the exception of NFSERR_WFLUSH which
diff --git a/net/sunrpc/backchannel_rqst.c b/net/sunrpc/backchannel_rqst.c
index 229956bf8457..95f82d8d4888 100644
--- a/net/sunrpc/backchannel_rqst.c
+++ b/net/sunrpc/backchannel_rqst.c
@@ -353,12 +353,20 @@ void xprt_complete_bc_request(struct rpc_rqst *req, uint32_t copied)
353{ 353{
354 struct rpc_xprt *xprt = req->rq_xprt; 354 struct rpc_xprt *xprt = req->rq_xprt;
355 struct svc_serv *bc_serv = xprt->bc_serv; 355 struct svc_serv *bc_serv = xprt->bc_serv;
356 struct xdr_buf *rq_rcv_buf = &req->rq_rcv_buf;
356 357
357 spin_lock(&xprt->bc_pa_lock); 358 spin_lock(&xprt->bc_pa_lock);
358 list_del(&req->rq_bc_pa_list); 359 list_del(&req->rq_bc_pa_list);
359 xprt_dec_alloc_count(xprt, 1); 360 xprt_dec_alloc_count(xprt, 1);
360 spin_unlock(&xprt->bc_pa_lock); 361 spin_unlock(&xprt->bc_pa_lock);
361 362
363 if (copied <= rq_rcv_buf->head[0].iov_len) {
364 rq_rcv_buf->head[0].iov_len = copied;
365 rq_rcv_buf->page_len = 0;
366 } else {
367 rq_rcv_buf->page_len = copied - rq_rcv_buf->head[0].iov_len;
368 }
369
362 req->rq_private_buf.len = copied; 370 req->rq_private_buf.len = copied;
363 set_bit(RPC_BC_PA_IN_USE, &req->rq_bc_pa_state); 371 set_bit(RPC_BC_PA_IN_USE, &req->rq_bc_pa_state);
364 372
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index bc5b7b5032ca..7fccf9675df8 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -1363,6 +1363,7 @@ bc_svc_process(struct svc_serv *serv, struct rpc_rqst *req,
1363 memcpy(&rqstp->rq_addr, &req->rq_xprt->addr, rqstp->rq_addrlen); 1363 memcpy(&rqstp->rq_addr, &req->rq_xprt->addr, rqstp->rq_addrlen);
1364 memcpy(&rqstp->rq_arg, &req->rq_rcv_buf, sizeof(rqstp->rq_arg)); 1364 memcpy(&rqstp->rq_arg, &req->rq_rcv_buf, sizeof(rqstp->rq_arg));
1365 memcpy(&rqstp->rq_res, &req->rq_snd_buf, sizeof(rqstp->rq_res)); 1365 memcpy(&rqstp->rq_res, &req->rq_snd_buf, sizeof(rqstp->rq_res));
1366 rqstp->rq_arg.len = req->rq_private_buf.len;
1366 1367
1367 /* reset result send buffer "put" position */ 1368 /* reset result send buffer "put" position */
1368 resv->iov_len = 0; 1369 resv->iov_len = 0;