[extracted from pnfsd: Initial pNFS server implementation.] Signed-off-by: Benny Halevy <bhalevy@xxxxxxxxxxx> [pnfsd: Streamline error code checking for non-pnfs filesystems] Signed-off-by: Dean Hildebrand <seattleplus@xxxxxxxxx> Signed-off-by: Benny Halevy <bhalevy@xxxxxxxxxxx> [pnfsd: update server layout xdr for draft 19.] Signed-off-by: Dean Hildebrand <dhildeb@xxxxxxxxxx> [pnfsd: use stateid_t for layout stateid xdr data structs] [pnfsd: use stateid xdr decode function for layoutcommit] [pnfsd: fix copy_clientid for layotucommit] [pnfsd: convert generic code to use new pnfs api] [pnfsd: define pnfs_export_operations] [pnfsd: obliterate old vfs api] [pnfsd: fixup ENCODE_HEAD for layoutcommit] Signed-off-by: Benny Halevy <bhalevy@xxxxxxxxxxx> [pnfsd: layout commit all layout types] Signed-off-by: Andy Adamson <andros@xxxxxxxxxx> [pnfsd: do not take the i_mutex when filesystem provides layout_commit] Signed-off-by: Benny Halevy <bhalevy@xxxxxxxxxxx> [pnfsd: check ex_pnfs in nfsd4_verify_layout] Signed-off-by: Andy Adamson <andros@xxxxxxxxxx> [pnfsd: fix cosmetic checkpatch warnings] [pnfsd: clean up layoutcommit export api] Signed-off-by: Benny Halevy <bhalevy@xxxxxxxxxxx> --- fs/nfsd/nfs4proc.c | 83 +++++++++++++++++++++++++++++++++++++++ fs/nfsd/nfs4xdr.c | 70 ++++++++++++++++++++++++++++++++- fs/nfsd/xdr4.h | 7 +++ include/linux/nfsd/nfsd4_pnfs.h | 21 ++++++++++ 4 files changed, 179 insertions(+), 2 deletions(-) diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 0336037..d05e260 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -1109,6 +1109,85 @@ nfsd4_layoutget(struct svc_rqst *rqstp, out: return status; } + +static __be32 +nfsd4_layoutcommit(struct svc_rqst *rqstp, + struct nfsd4_compound_state *cstate, + struct nfsd4_pnfs_layoutcommit *lcp) +{ + int status; + struct inode *ino = NULL; + struct iattr ia; + struct super_block *sb; + struct svc_fh *current_fh = &cstate->current_fh; + + dprintk("NFSD: nfsd4_layoutcommit \n"); + status = fh_verify(rqstp, current_fh, 0, NFSD_MAY_NOP); + if (status) + goto out; + + status = nfserr_inval; + ino = current_fh->fh_dentry->d_inode; + if (!ino) + goto out; + + status = nfserr_inval; + sb = ino->i_sb; + if (!sb) + goto out; + + /* Ensure underlying file system supports pNFS and, + * if so, the requested layout type + */ + status = nfsd4_layout_verify(sb, current_fh->fh_export, + lcp->args.lc_seg.layout_type); + if (status) + goto out; + + /* This will only extend the file length. Do a quick + * check to see if there is any point in waiting for the update + * locks. + * TODO: Is this correct for all back ends? + */ + dprintk("%s:new offset: %d new size: %llu old size: %lld\n", + __func__, lcp->args.lc_newoffset, lcp->args.lc_last_wr + 1, + ino->i_size); + + /* Set clientid from sessionid */ + copy_clientid((clientid_t *)&lcp->args.lc_seg.clientid, cstate->session); + lcp->res.lc_size_chg = 0; + if (sb->s_pnfs_op->layout_commit) { + status = sb->s_pnfs_op->layout_commit(ino, &lcp->args, &lcp->res); + dprintk("%s:layout_commit result %d\n", __func__, status); + } else { + fh_lock(current_fh); + if ((lcp->args.lc_newoffset == 0) || + ((lcp->args.lc_last_wr + 1) <= ino->i_size)) { + status = 0; + lcp->res.lc_size_chg = 0; + fh_unlock(current_fh); + goto out; + } + + /* Try our best to update the file size */ + dprintk("%s: Modifying file size\n", __func__); + ia.ia_valid = ATTR_SIZE; + ia.ia_size = lcp->args.lc_last_wr + 1; + status = notify_change(current_fh->fh_dentry, &ia); + fh_unlock(current_fh); + dprintk("%s:notify_change result %d\n", __func__, status); + } + + if (!status && lcp->res.lc_size_chg && + EX_ISSYNC(current_fh->fh_export)) { + dprintk("%s: Synchronously writing inode size %llu\n", + __func__, ino->i_size); + write_inode_now(ino, 1); + lcp->res.lc_newsize = i_size_read(ino); + } +out: + return status; +} #endif /* CONFIG_PNFSD */ /* @@ -1485,6 +1564,10 @@ static struct nfsd4_operation nfsd4_ops[] = { .op_func = (nfsd4op_func)nfsd4_layoutget, .op_name = "OP_LAYOUTGET", }, + [OP_LAYOUTCOMMIT] = { + .op_func = (nfsd4op_func)nfsd4_layoutcommit, + .op_name = "OP_LAYOUTCOMMIT", + }, #endif /* CONFIG_PNFSD */ }; diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 40c794a..96f6567 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -1290,6 +1290,51 @@ nfsd4_decode_layoutget(struct nfsd4_compoundargs *argp, DECODE_TAIL; } + +static __be32 +nfsd4_decode_layoutcommit(struct nfsd4_compoundargs *argp, + struct nfsd4_pnfs_layoutcommit *lcp) +{ + DECODE_HEAD; + u32 timechange; + + READ_BUF(20); + READ64(lcp->args.lc_seg.offset); + READ64(lcp->args.lc_seg.length); + READ32(lcp->args.lc_reclaim); + nfsd4_decode_stateid(argp, &lcp->lc_sid); + READ_BUF(4); + READ32(lcp->args.lc_newoffset); + if (lcp->args.lc_newoffset) { + READ_BUF(8); + READ64(lcp->args.lc_last_wr); + } else + lcp->args.lc_last_wr = 0; + READ_BUF(4); + READ32(timechange); + if (timechange) { + READ_BUF(12); + READ64(lcp->args.lc_mtime.seconds); + READ32(lcp->args.lc_mtime.nseconds); + } else { + lcp->args.lc_mtime.seconds = 0; + lcp->args.lc_mtime.nseconds = 0; + } + READ_BUF(8); + READ32(lcp->args.lc_seg.layout_type); + /* XXX: saving XDR'ed layout update. Since we don't have the + * current_fh yet, and therefore no export_ops, we can't call + * the layout specific decode routines. File and pVFS2 + * do not use the layout update.... + */ + READ32(lcp->args.lc_up_len); + if (lcp->args.lc_up_len > 0) { + READ_BUF(lcp->args.lc_up_len); + READMEM(lcp->args.lc_up_layout, lcp->args.lc_up_len); + } + + DECODE_TAIL; +} #endif /* CONFIG_PNFSD */ static __be32 @@ -1396,7 +1441,7 @@ static nfsd4_dec nfsd41_dec_ops[] = { #if defined(CONFIG_PNFSD) [OP_GETDEVICEINFO] = (nfsd4_dec)nfsd4_decode_getdevinfo, [OP_GETDEVICELIST] = (nfsd4_dec)nfsd4_decode_getdevlist, - [OP_LAYOUTCOMMIT] = (nfsd4_dec)nfsd4_decode_notsupp, + [OP_LAYOUTCOMMIT] = (nfsd4_dec)nfsd4_decode_layoutcommit, [OP_LAYOUTGET] = (nfsd4_dec)nfsd4_decode_layoutget, [OP_LAYOUTRETURN] = (nfsd4_dec)nfsd4_decode_notsupp, #else /* CONFIG_PNFSD */ @@ -3436,6 +3481,27 @@ err: resp->p = p_start; return nfserr; } + +static __be32 +nfsd4_encode_layoutcommit(struct nfsd4_compoundres *resp, int nfserr, + struct nfsd4_pnfs_layoutcommit *lcp) +{ + __be32 *p; + + if (nfserr) + goto out; + + RESERVE_SPACE(4); + WRITE32(lcp->res.lc_size_chg); + ADJUST_ARGS(); + if (lcp->res.lc_size_chg) { + RESERVE_SPACE(8); + WRITE64(lcp->res.lc_newsize); + ADJUST_ARGS(); + } +out: + return nfserr; +} #endif /* CONFIG_PNFSD */ static __be32 @@ -3501,7 +3567,7 @@ static nfsd4_enc nfsd4_enc_ops[] = { #if defined(CONFIG_PNFSD) [OP_GETDEVICEINFO] = (nfsd4_enc)nfsd4_encode_getdevinfo, [OP_GETDEVICELIST] = (nfsd4_enc)nfsd4_encode_getdevlist, - [OP_LAYOUTCOMMIT] = (nfsd4_enc)nfsd4_encode_noop, + [OP_LAYOUTCOMMIT] = (nfsd4_enc)nfsd4_encode_layoutcommit, [OP_LAYOUTGET] = (nfsd4_enc)nfsd4_encode_layoutget, [OP_LAYOUTRETURN] = (nfsd4_enc)nfsd4_encode_noop, #else /* CONFIG_PNFSD */ diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h index 891f3d2..19a94e2 100644 --- a/fs/nfsd/xdr4.h +++ b/fs/nfsd/xdr4.h @@ -411,6 +411,12 @@ struct nfsd4_pnfs_layoutget { u32 lg_roc; /* response */ }; +struct nfsd4_pnfs_layoutcommit { + struct nfsd4_pnfs_layoutcommit_arg args; + stateid_t lc_sid; /* request */ + struct nfsd4_pnfs_layoutcommit_res res; +}; + struct nfsd4_op { int opnum; __be32 status; @@ -455,6 +461,7 @@ struct nfsd4_op { struct nfsd4_pnfs_getdevlist pnfs_getdevlist; struct nfsd4_pnfs_getdevinfo pnfs_getdevinfo; struct nfsd4_pnfs_layoutget pnfs_layoutget; + struct nfsd4_pnfs_layoutcommit pnfs_layoutcommit; #endif /* CONFIG_PNFSD */ } u; struct nfs4_replay * replay; diff --git a/include/linux/nfsd/nfsd4_pnfs.h b/include/linux/nfsd/nfsd4_pnfs.h index b80ff01..69c43f6 100644 --- a/include/linux/nfsd/nfsd4_pnfs.h +++ b/include/linux/nfsd/nfsd4_pnfs.h @@ -36,6 +36,7 @@ #include <linux/exportfs.h> #include <linux/exp_xdr.h> +#include <linux/nfs_xdr.h> #include <linux/nfsd/nfsfh.h> struct nfsd4_pnfs_deviceid { @@ -80,6 +81,21 @@ struct nfsd4_pnfs_layoutget_res { u32 lg_return_on_close; }; +struct nfsd4_pnfs_layoutcommit_arg { + struct nfsd4_layout_seg lc_seg; /* request */ + u32 lc_reclaim; /* request */ + u32 lc_newoffset; /* request */ + u64 lc_last_wr; /* request */ + struct nfstime4 lc_mtime; /* request */ + u32 lc_up_len; /* layout length */ + void *lc_up_layout; /* decoded by callback */ +}; + +struct nfsd4_pnfs_layoutcommit_res { + u32 lc_size_chg; /* boolean for response */ + u64 lc_newsize; /* response */ +}; + /* * pNFS export operations vector. * @@ -130,6 +146,11 @@ struct pnfs_export_operations { const struct nfsd4_pnfs_layoutget_arg *, struct nfsd4_pnfs_layoutget_res *); + /* Commit changes to layout */ + int (*layout_commit) (struct inode *, + const struct nfsd4_pnfs_layoutcommit_arg *, + struct nfsd4_pnfs_layoutcommit_res *); + /* Can layout segments be merged for this layout type? */ int (*can_merge_layouts) (u32 layout_type); }; -- 1.6.5.1 -- To unsubscribe from this list: send the line "unsubscribe linux-nfs" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html