Skip to content

Commit 8003a57

Browse files
committed
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
2 parents d0bc387 + 4f2e9dc commit 8003a57

File tree

12 files changed

+87
-75
lines changed

12 files changed

+87
-75
lines changed

fs/nfs/callback_xdr.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,8 @@ static __be32 *read_buf(struct xdr_stream *xdr, int nbytes)
7878

7979
p = xdr_inline_decode(xdr, nbytes);
8080
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");
8283
return p;
8384
}
8485

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

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

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);
904907

905908
p = (__be32*)((char *)rqstp->rq_res.head[0].iov_base + rqstp->rq_res.head[0].iov_len);
906909
xdr_init_encode(&xdr_out, &rqstp->rq_res, p);

fs/nfs/inode.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -618,7 +618,10 @@ void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr,
618618
nfs_inc_stats(inode, NFSIOS_SETATTRTRUNC);
619619
nfs_vmtruncate(inode, attr->ia_size);
620620
}
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;
622625
spin_unlock(&inode->i_lock);
623626
}
624627
EXPORT_SYMBOL_GPL(nfs_setattr_update_inode);
@@ -1824,7 +1827,11 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
18241827
if ((long)fattr->gencount - (long)nfsi->attr_gencount > 0)
18251828
nfsi->attr_gencount = fattr->gencount;
18261829
}
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+
18281835
/* Don't invalidate the data if we were to blame */
18291836
if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode)
18301837
|| S_ISLNK(inode->i_mode)))

fs/nfs/nfs42proc.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
#include "pnfs.h"
1515
#include "internal.h"
1616

17-
#define NFSDBG_FACILITY NFSDBG_PNFS
17+
#define NFSDBG_FACILITY NFSDBG_PROC
1818

1919
static int nfs42_set_rw_stateid(nfs4_stateid *dst, struct file *file,
2020
fmode_t fmode)
@@ -284,6 +284,7 @@ static int _nfs42_proc_clone(struct rpc_message *msg, struct file *src_f,
284284
.dst_fh = NFS_FH(dst_inode),
285285
.src_offset = src_offset,
286286
.dst_offset = dst_offset,
287+
.count = count,
287288
.dst_bitmask = server->cache_consistency_bitmask,
288289
};
289290
struct nfs42_clone_res res = {

fs/nfs/nfs4client.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ static int nfs_get_cb_ident_idr(struct nfs_client *clp, int minorversion)
3333
return ret;
3434
idr_preload(GFP_KERNEL);
3535
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);
3737
if (ret >= 0)
3838
clp->cl_cb_ident = ret;
3939
spin_unlock(&nn->nfs_client_lock);

fs/nfs/nfs4file.c

Lines changed: 27 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <linux/file.h>
88
#include <linux/falloc.h>
99
#include <linux/nfs_fs.h>
10+
#include <uapi/linux/btrfs.h> /* BTRFS_IOC_CLONE/BTRFS_IOC_CLONE_RANGE */
1011
#include "delegation.h"
1112
#include "internal.h"
1213
#include "iostat.h"
@@ -203,6 +204,7 @@ nfs42_ioctl_clone(struct file *dst_file, unsigned long srcfd,
203204
struct fd src_file;
204205
struct inode *src_inode;
205206
unsigned int bs = server->clone_blksize;
207+
bool same_inode = false;
206208
int ret;
207209

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

222224
src_inode = file_inode(src_file.file);
223225

224-
/* src and dst must be different files */
225-
ret = -EINVAL;
226226
if (src_inode == dst_inode)
227-
goto out_fput;
227+
same_inode = true;
228228

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

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+
252258
/* 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) {
254262
mutex_lock_nested(&dst_inode->i_mutex, I_MUTEX_PARENT);
255263
mutex_lock_nested(&src_inode->i_mutex, I_MUTEX_CHILD);
256264
} else {
@@ -275,7 +283,9 @@ nfs42_ioctl_clone(struct file *dst_file, unsigned long srcfd,
275283
truncate_inode_pages_range(&dst_inode->i_data, dst_off, dst_off + count - 1);
276284

277285
out_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) {
279289
mutex_unlock(&src_inode->i_mutex);
280290
mutex_unlock(&dst_inode->i_mutex);
281291
} else {
@@ -291,46 +301,31 @@ nfs42_ioctl_clone(struct file *dst_file, unsigned long srcfd,
291301

292302
static long nfs42_ioctl_clone_range(struct file *dst_file, void __user *argp)
293303
{
294-
struct nfs_ioctl_clone_range_args args;
304+
struct btrfs_ioctl_clone_range_args args;
295305

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

299-
return nfs42_ioctl_clone(dst_file, args.src_fd, args.src_off, args.dst_off, args.count);
300-
}
301-
#else
302-
static 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-
308-
static long nfs42_ioctl_clone_range(struct file *dst_file, void __user *argp)
309-
{
310-
return -ENOTTY;
309+
return nfs42_ioctl_clone(dst_file, args.src_fd, args.src_offset,
310+
args.dest_offset, args.src_length);
311311
}
312-
#endif /* CONFIG_NFS_V4_2 */
313312

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

318317
switch (cmd) {
319-
case NFS_IOC_CLONE:
318+
case BTRFS_IOC_CLONE:
320319
return nfs42_ioctl_clone(file, arg, 0, 0, 0);
321-
case NFS_IOC_CLONE_RANGE:
320+
case BTRFS_IOC_CLONE_RANGE:
322321
return nfs42_ioctl_clone_range(file, argp);
323322
}
324323

325324
return -ENOTTY;
326325
}
326+
#endif /* CONFIG_NFS_V4_2 */
327327

328328
const 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
334329
.read_iter = nfs_file_read,
335330
.write_iter = nfs_file_write,
336331
.mmap = nfs_file_mmap,
@@ -342,14 +337,14 @@ const struct file_operations nfs4_file_operations = {
342337
.flock = nfs_flock,
343338
.splice_read = nfs_file_splice_read,
344339
.splice_write = iter_file_splice_write,
345-
#ifdef CONFIG_NFS_V4_2
346-
.fallocate = nfs42_fallocate,
347-
#endif /* CONFIG_NFS_V4_2 */
348340
.check_flags = nfs_check_flags,
349341
.setlease = simple_nosetlease,
350-
#ifdef CONFIG_COMPAT
342+
#ifdef CONFIG_NFS_V4_2
343+
.llseek = nfs4_file_llseek,
344+
.fallocate = nfs42_fallocate,
351345
.unlocked_ioctl = nfs4_ioctl,
352-
#else
353346
.compat_ioctl = nfs4_ioctl,
354-
#endif /* CONFIG_COMPAT */
347+
#else
348+
.llseek = nfs_file_llseek,
349+
#endif
355350
};

fs/nfs/nfs4proc.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7866,7 +7866,7 @@ static void nfs4_layoutget_done(struct rpc_task *task, void *calldata)
78667866
spin_unlock(&inode->i_lock);
78677867
goto out_restart;
78687868
}
7869-
if (nfs4_async_handle_error(task, server, state, NULL) == -EAGAIN)
7869+
if (nfs4_async_handle_error(task, server, state, &lgp->timeout) == -EAGAIN)
78707870
goto out_restart;
78717871
out:
78727872
dprintk("<-- %s\n", __func__);

fs/nfs/nfs4xdr.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3615,6 +3615,7 @@ static int decode_attr_fs_locations(struct xdr_stream *xdr, uint32_t *bitmap, st
36153615
status = 0;
36163616
if (unlikely(!(bitmap[0] & FATTR4_WORD0_FS_LOCATIONS)))
36173617
goto out;
3618+
bitmap[0] &= ~FATTR4_WORD0_FS_LOCATIONS;
36183619
status = -EIO;
36193620
/* Ignore borken servers that return unrequested attrs */
36203621
if (unlikely(res == NULL))

fs/nfs/pnfs.c

Lines changed: 31 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -872,33 +872,38 @@ send_layoutget(struct pnfs_layout_hdr *lo,
872872

873873
dprintk("--> %s\n", __func__);
874874

875-
lgp = kzalloc(sizeof(*lgp), gfp_flags);
876-
if (lgp == NULL)
877-
return NULL;
875+
/*
876+
* Synchronously retrieve layout information from server and
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;
878903

879-
i_size = i_size_read(ino);
904+
lseg = nfs4_proc_layoutget(lgp, gfp_flags);
905+
} while (lseg == ERR_PTR(-EAGAIN));
880906

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);
902907
if (IS_ERR(lseg)) {
903908
switch (PTR_ERR(lseg)) {
904909
case -ENOMEM:
@@ -1687,6 +1692,7 @@ pnfs_layout_process(struct nfs4_layoutget *lgp)
16871692
/* existing state ID, make sure the sequence number matches. */
16881693
if (pnfs_layout_stateid_blocked(lo, &res->stateid)) {
16891694
dprintk("%s forget reply due to sequence\n", __func__);
1695+
status = -EAGAIN;
16901696
goto out_forget_reply;
16911697
}
16921698
pnfs_set_layout_stateid(lo, &res->stateid, false);

include/linux/nfs_xdr.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,7 @@ struct nfs4_layoutget {
251251
struct nfs4_layoutget_res res;
252252
struct rpc_cred *cred;
253253
gfp_t gfp_flags;
254+
long timeout;
254255
};
255256

256257
struct nfs4_getdeviceinfo_args {

include/uapi/linux/nfs.h

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -33,17 +33,6 @@
3333

3434
#define NFS_PIPE_DIRNAME "nfs"
3535

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-
41-
struct nfs_ioctl_clone_range_args {
42-
__s64 src_fd;
43-
__u64 src_off, count;
44-
__u64 dst_off;
45-
};
46-
4736
/*
4837
* NFS stats. The good thing with these values is that NFSv3 errors are
4938
* a superset of NFSv2 errors (with the exception of NFSERR_WFLUSH which

net/sunrpc/backchannel_rqst.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,12 +353,20 @@ void xprt_complete_bc_request(struct rpc_rqst *req, uint32_t copied)
353353
{
354354
struct rpc_xprt *xprt = req->rq_xprt;
355355
struct svc_serv *bc_serv = xprt->bc_serv;
356+
struct xdr_buf *rq_rcv_buf = &req->rq_rcv_buf;
356357

357358
spin_lock(&xprt->bc_pa_lock);
358359
list_del(&req->rq_bc_pa_list);
359360
xprt_dec_alloc_count(xprt, 1);
360361
spin_unlock(&xprt->bc_pa_lock);
361362

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+
362370
req->rq_private_buf.len = copied;
363371
set_bit(RPC_BC_PA_IN_USE, &req->rq_bc_pa_state);
364372

net/sunrpc/svc.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1363,6 +1363,7 @@ bc_svc_process(struct svc_serv *serv, struct rpc_rqst *req,
13631363
memcpy(&rqstp->rq_addr, &req->rq_xprt->addr, rqstp->rq_addrlen);
13641364
memcpy(&rqstp->rq_arg, &req->rq_rcv_buf, sizeof(rqstp->rq_arg));
13651365
memcpy(&rqstp->rq_res, &req->rq_snd_buf, sizeof(rqstp->rq_res));
1366+
rqstp->rq_arg.len = req->rq_private_buf.len;
13661367

13671368
/* reset result send buffer "put" position */
13681369
resv->iov_len = 0;

0 commit comments

Comments
 (0)