Skip to content

Commit d12f38a

Browse files
sbashirogregkh
authored andcommitted
NFSD: Fix last write offset handling in layoutcommit
[ Upstream commit d68886bae76a4b9b3484d23e5b7df086f940fa38 ] The data type of loca_last_write_offset is newoffset4 and is switched on a boolean value, no_newoffset, that indicates if a previous write occurred or not. If no_newoffset is FALSE, an offset is not given. This means that client does not try to update the file size. Thus, server should not try to calculate new file size and check if it fits into the segment range. See RFC 8881, section 12.5.4.2. Sometimes the current incorrect logic may cause clients to hang when trying to sync an inode. If layoutcommit fails, the client marks the inode as dirty again. Fixes: 9cf514c ("nfsd: implement pNFS operations") Cc: [email protected] Co-developed-by: Konstantin Evtushenko <[email protected]> Signed-off-by: Konstantin Evtushenko <[email protected]> Signed-off-by: Sergey Bashirov <[email protected]> Reviewed-by: Christoph Hellwig <[email protected]> Reviewed-by: Jeff Layton <[email protected]> Signed-off-by: Chuck Lever <[email protected]> Signed-off-by: Sasha Levin <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 58e4050 commit d12f38a

2 files changed

Lines changed: 17 additions & 18 deletions

File tree

fs/nfsd/blocklayout.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,6 @@ nfsd4_block_commit_blocks(struct inode *inode, struct nfsd4_layoutcommit *lcp,
118118
struct iomap *iomaps, int nr_iomaps)
119119
{
120120
struct timespec64 mtime = inode_get_mtime(inode);
121-
loff_t new_size = lcp->lc_last_wr + 1;
122121
struct iattr iattr = { .ia_valid = 0 };
123122
int error;
124123

@@ -128,9 +127,9 @@ nfsd4_block_commit_blocks(struct inode *inode, struct nfsd4_layoutcommit *lcp,
128127
iattr.ia_valid |= ATTR_ATIME | ATTR_CTIME | ATTR_MTIME;
129128
iattr.ia_atime = iattr.ia_ctime = iattr.ia_mtime = lcp->lc_mtime;
130129

131-
if (new_size > i_size_read(inode)) {
130+
if (lcp->lc_size_chg) {
132131
iattr.ia_valid |= ATTR_SIZE;
133-
iattr.ia_size = new_size;
132+
iattr.ia_size = lcp->lc_newsize;
134133
}
135134

136135
error = inode->i_sb->s_export_op->commit_blocks(inode, iomaps,

fs/nfsd/nfs4proc.c

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2504,7 +2504,6 @@ nfsd4_layoutcommit(struct svc_rqst *rqstp,
25042504
const struct nfsd4_layout_seg *seg = &lcp->lc_seg;
25052505
struct svc_fh *current_fh = &cstate->current_fh;
25062506
const struct nfsd4_layout_ops *ops;
2507-
loff_t new_size = lcp->lc_last_wr + 1;
25082507
struct inode *inode;
25092508
struct nfs4_layout_stateid *ls;
25102509
__be32 nfserr;
@@ -2520,13 +2519,21 @@ nfsd4_layoutcommit(struct svc_rqst *rqstp,
25202519
goto out;
25212520
inode = d_inode(current_fh->fh_dentry);
25222521

2523-
nfserr = nfserr_inval;
2524-
if (new_size <= seg->offset)
2525-
goto out;
2526-
if (new_size > seg->offset + seg->length)
2527-
goto out;
2528-
if (!lcp->lc_newoffset && new_size > i_size_read(inode))
2529-
goto out;
2522+
lcp->lc_size_chg = false;
2523+
if (lcp->lc_newoffset) {
2524+
loff_t new_size = lcp->lc_last_wr + 1;
2525+
2526+
nfserr = nfserr_inval;
2527+
if (new_size <= seg->offset)
2528+
goto out;
2529+
if (new_size > seg->offset + seg->length)
2530+
goto out;
2531+
2532+
if (new_size > i_size_read(inode)) {
2533+
lcp->lc_size_chg = true;
2534+
lcp->lc_newsize = new_size;
2535+
}
2536+
}
25302537

25312538
nfserr = nfsd4_preprocess_layout_stateid(rqstp, cstate, &lcp->lc_sid,
25322539
false, lcp->lc_layout_type,
@@ -2542,13 +2549,6 @@ nfsd4_layoutcommit(struct svc_rqst *rqstp,
25422549
/* LAYOUTCOMMIT does not require any serialization */
25432550
mutex_unlock(&ls->ls_mutex);
25442551

2545-
if (new_size > i_size_read(inode)) {
2546-
lcp->lc_size_chg = true;
2547-
lcp->lc_newsize = new_size;
2548-
} else {
2549-
lcp->lc_size_chg = false;
2550-
}
2551-
25522552
nfserr = ops->proc_layoutcommit(inode, rqstp, lcp);
25532553
nfs4_put_stid(&ls->ls_stid);
25542554
out:

0 commit comments

Comments
 (0)