[pnfs] [PATCH 19/28] pnfs: pnfs_write_begin
Benny Halevy
bhalevy at panasas.com
Thu Mar 13 10:13:31 EDT 2008
On Mar. 11, 2008, 21:32 +0200, Fred Isaman <iisaman at citi.umich.edu> wrote:
> From: Fred <iisaman at citi.umich.edu>
>
> Add hooks in the nfs_write_begin path, giving a driver the potential
> to read in page data around the data that is about to be copied to the page.
>
> Signed-off-by: Fred <iisaman at citi.umich.edu>
> ---
> fs/nfs/file.c | 20 ++++++++--
> fs/nfs/pnfs.c | 88 +++++++++++++++++++++++++++++++++++++++++++++
> fs/nfs/pnfs.h | 10 +++++
> fs/nfs/write.c | 2 +-
> include/linux/nfs4_pnfs.h | 15 +++++++-
> 5 files changed, 129 insertions(+), 6 deletions(-)
>
> diff --git a/fs/nfs/file.c b/fs/nfs/file.c
> index 6f16772..e870982 100644
> --- a/fs/nfs/file.c
> +++ b/fs/nfs/file.c
> @@ -352,10 +352,19 @@ static int nfs_write_begin(struct file *file, struct address_space *mapping,
> *pagep = page;
>
> ret = nfs_flush_incompatible(file, page);
> - if (ret) {
> - unlock_page(page);
> - page_cache_release(page);
> - }
> + if (ret)
> + goto out_err;
> +#ifdef CONFIG_PNFS
> + ret = pnfs_write_begin(file, page, pos, len, flags, fsdata);
> + if (ret)
> + goto out_err;
> +#endif /* CONFIG_PNFS */
> + return 0;
> +
> + out_err:
> + unlock_page(page);
> + page_cache_release(page);
> + *pagep = NULL;
> return ret;
> }
>
> @@ -372,6 +381,9 @@ static int nfs_write_end(struct file *file, struct address_space *mapping,
>
> unlock_page(page);
> page_cache_release(page);
> +#ifdef CONFIG_PNFS
> + pnfs_free_fsdata(fsdata);
> +#endif /* CONFIG_PNFS */
>
> return status < 0 ? status : copied;
> }
> diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c
> index 56aa1bf..a4db86e 100644
> --- a/fs/nfs/pnfs.c
> +++ b/fs/nfs/pnfs.c
> @@ -809,6 +809,28 @@ pnfs_has_layout(struct pnfs_layout_type *lo,
> return ret;
> }
>
> +static struct pnfs_layout_segment *
> +pnfs_find_get_lseg(struct inode *inode,
> + loff_t pos,
> + size_t count,
> + enum pnfs_iomode iomode)
> +{
> + struct nfs_inode *nfsi = NFS_I(inode);
> + struct pnfs_layout_segment *lseg;
> + struct pnfs_layout_type *lo;
> + struct nfs4_pnfs_layout_segment range;
> +
> + lo = get_lock_current_layout(nfsi);
> + if (!lo)
> + return NULL;
> + range.iomode = iomode;
> + range.offset = pos;
> + range.length = count;
> + lseg = pnfs_has_layout(lo, &range, 1);
> + put_unlock_current_layout(nfsi, lo);
> + return lseg;
> +}
> +
> /* Update the file's layout for the given range and iomode.
> * Layout is retreived from the server if needed.
> * If lsegpp is given, the appropriate layout segment is referenced and
> @@ -1537,6 +1559,64 @@ int pnfs_try_to_read_data(struct nfs_read_data *data,
> }
> }
>
> +/*
> + * This gives the layout driver an opportunity to read in page "around"
> + * the data to be written. It returns 0 on success, otherwise an error code
> + * which will either be passed up to user, or ignored if
> + * some previous part of write succeeded.
> + * Note the range [pos, pos+len-1] is entirely within the page.
> + */
> +/* flags = AOP_FLAG_UNINTERRUPTIBLE or 0 - ??? need this ??? */
> +int pnfs_write_begin(struct file *filp, struct page *page,
> + loff_t pos, unsigned len,
> + unsigned flags, void **fsdata)
> +{
> + struct inode *inode = filp->f_dentry->d_inode;
> + struct nfs_server *nfss = NFS_SERVER(inode);
> + struct pnfs_layout_segment *lseg;
> + struct pnfs_fsdata *pnfs_fsdata = NULL;
> + int status = 0;
> +
> + if (!nfss->pnfs_curr_ld || !nfss->pnfs_curr_ld->ld_io_ops ||
> + !nfss->pnfs_curr_ld->ld_io_ops->write_begin) {
> + /* If layout driver doesn't define, just do nothing */
> + goto out;
> + }
> + lseg = pnfs_find_get_lseg(inode, pos, len, IOMODE_RW);
> + status = nfss->pnfs_curr_ld->ld_io_ops->write_begin(lseg, page,
> + pos, len,
> + &pnfs_fsdata);
> + put_lseg(lseg);
> + if (pnfs_fsdata && !pnfs_fsdata->ld_io_ops)
> + pnfs_fsdata->ld_io_ops = nfss->pnfs_curr_ld->ld_io_ops;
> + out:
> + *fsdata = pnfs_fsdata;
One more comment. Can fsdata be NULL?
Benny
More information about the pNFS
mailing list